home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / bin / DXUtils / AppWizard / DXAppwiz.awx / TEMPLATE / D3D_WIN.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-25  |  98.4 KB  |  2,744 lines

  1. //-----------------------------------------------------------------------------
  2. // File: $$root$$.cpp
  3. //
  4. // Desc: DirectX window application created by the DirectX AppWizard
  5. //-----------------------------------------------------------------------------
  6. #define STRICT
  7. $$IF(DINPUT)
  8. #define DIRECTINPUT_VERSION 0x0800
  9. $$ENDIF
  10. #include <windows.h>
  11. #include <basetsd.h>
  12. #include <math.h>
  13. #include <stdio.h>
  14. #include <D3DX8.h>
  15. #include <DXErr8.h>
  16. #include <tchar.h>
  17. $$IF(DINPUT)
  18. #include <dinput.h>
  19. $$ENDIF
  20. $$IF(DPLAY)
  21. #include <dplay8.h>
  22. #include <dplobby8.h>
  23. $$ENDIF
  24. #include "D3DApp.h"
  25. $$IF(D3DFONT)
  26. #include "D3DFont.h"
  27. $$ENDIF
  28. $$IF(X_FILE)
  29. #include "D3DFile.h"
  30. $$ENDIF
  31. #include "D3DUtil.h"
  32. $$IF(ACTIONMAPPER)
  33. #include "DIUtil.h"
  34. $$ENDIF
  35. $$IF(DMUSIC)
  36. #include "DMUtil.h"
  37. $$ENDIF
  38. $$IF(DSOUND)
  39. #include "DSUtil.h"
  40. $$ENDIF
  41. $$IF(DPLAY)
  42. #include "NetConnect.h"
  43. $$ENDIF
  44. $$IF(DPLAYVOICE)
  45. #include "NetVoice.h"
  46. $$ENDIF
  47. #include "DXUtil.h"
  48. #include "resource.h"
  49. #include "$$root$$.h"
  50.  
  51.  
  52.  
  53. $$IF(ACTIONMAPPER|DPLAY)
  54. //-----------------------------------------------------------------------------
  55. // Defines, and constants
  56. //-----------------------------------------------------------------------------
  57. // This GUID must be unique for every game, and the same for 
  58. // every instance of this app.  // $$GUIDMSG$$
  59. $$IF(DPLAY)
  60. // The GUID allows DirectPlay to find other instances of the same game on
  61. // the network.  
  62. $$ENDIF // end DPLAY
  63. $$IF(ACTIONMAPPER)
  64. // The GUID allows DirectInput to remember input settings
  65. $$ENDIF // end ACTIONMAPPER
  66. GUID g_guidApp = $$GUIDSTRUCT$$;
  67.  
  68.  
  69. $$ENDIF // end (ACTIONMAPPER|DPLAY)
  70. $$IF(ACTIONMAPPER)
  71. // Input semantics used by this app
  72. enum INPUT_SEMANTICS
  73. {
  74.     // Gameplay semantics
  75.     // TODO: change as needed
  76.     INPUT_ROTATE_AXIS_LR=1, INPUT_ROTATE_AXIS_UD,       
  77.     INPUT_ROTATE_LEFT,      INPUT_ROTATE_RIGHT,    
  78.     INPUT_ROTATE_UP,        INPUT_ROTATE_DOWN,
  79.     INPUT_CONFIG_INPUT,     INPUT_CONFIG_DISPLAY,
  80. $$IF(DPLAYVOICE)
  81.     INPUT_CONFIG_VOICE,     
  82. $$ENDIF
  83. $$IF(DMUSIC || DSOUND)
  84.     INPUT_PLAY_SOUND,       
  85. $$ENDIF
  86. };
  87.  
  88. // Actions used by this app
  89. DIACTION g_rgGameAction[] =
  90. {
  91.     // TODO: change as needed.  Be sure to delete user map files 
  92.     // (C:\Program Files\DirectX\DirectInput\User Maps\*.ini)
  93.     // after changing this, otherwise settings won't reset and will be read 
  94.     // from the out of date ini files 
  95.  
  96.     // Device input (joystick, etc.) that is pre-defined by DInput, according
  97.     // to genre type. The genre for this app is space simulators.
  98.     { INPUT_ROTATE_AXIS_LR,  DIAXIS_3DCONTROL_LATERAL,      0, TEXT("Rotate left/right"), },
  99.     { INPUT_ROTATE_AXIS_UD,  DIAXIS_3DCONTROL_MOVE,         0, TEXT("Rotate up/down"), },
  100. $$IF(DMUSIC || DSOUND)
  101.     { INPUT_PLAY_SOUND,      DIBUTTON_3DCONTROL_SPECIAL,    0, TEXT("Play sound"), },
  102. $$ENDIF
  103.  
  104.     // Keyboard input mappings
  105.     { INPUT_ROTATE_LEFT,     DIKEYBOARD_LEFT,               0, TEXT("Rotate left"), },
  106.     { INPUT_ROTATE_RIGHT,    DIKEYBOARD_RIGHT,              0, TEXT("Rotate right"), },
  107.     { INPUT_ROTATE_UP,       DIKEYBOARD_UP,                 0, TEXT("Rotate up"), },
  108.     { INPUT_ROTATE_DOWN,     DIKEYBOARD_DOWN,               0, TEXT("Rotate down"), },
  109. $$IF(DMUSIC || DSOUND)
  110.     { INPUT_PLAY_SOUND,      DIKEYBOARD_F5,                 0, TEXT("Play sound"), },
  111. $$ENDIF
  112.     { INPUT_CONFIG_DISPLAY,  DIKEYBOARD_F2,                 DIA_APPFIXED, TEXT("Configure Display"), },    
  113.     { INPUT_CONFIG_INPUT,    DIKEYBOARD_F3,                 DIA_APPFIXED, TEXT("Configure Input"), },    
  114. $$IF(DPLAYVOICE)
  115.     { INPUT_CONFIG_VOICE,    DIKEYBOARD_F4,                 DIA_APPFIXED, TEXT("Configure Voice"), },    
  116. $$ENDIF
  117. };
  118.  
  119. #define NUMBER_OF_GAMEACTIONS    (sizeof(g_rgGameAction)/sizeof(DIACTION))
  120.  
  121.  
  122.  
  123.  
  124. $$ENDIF
  125. //-----------------------------------------------------------------------------
  126. // Global access to the app (needed for the global WndProc())
  127. //-----------------------------------------------------------------------------
  128. CMyD3DApplication* g_pApp  = NULL;
  129. HINSTANCE          g_hInst = NULL;
  130.  
  131.  
  132.  
  133.  
  134. //-----------------------------------------------------------------------------
  135. // Name: WinMain()
  136. // Desc: Entry point to the program. Initializes everything, and goes into a
  137. //       message-processing loop. Idle time is used to render the scene.
  138. //-----------------------------------------------------------------------------
  139. INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT )
  140. {
  141.     CMyD3DApplication d3dApp;
  142.  
  143.     g_pApp  = &d3dApp;
  144.     g_hInst = hInst;
  145.  
  146.     if( FAILED( d3dApp.Create( hInst ) ) )
  147.         return 0;
  148.  
  149.     return d3dApp.Run();
  150. }
  151.  
  152.  
  153.  
  154.  
  155. //-----------------------------------------------------------------------------
  156. // Name: CMyD3DApplication()
  157. // Desc: Application constructor. Sets attributes for the app.
  158. //-----------------------------------------------------------------------------
  159. CMyD3DApplication::CMyD3DApplication()
  160. {
  161.     m_dwCreationWidth           = 500;
  162.     m_dwCreationHeight          = 375;
  163.     m_strWindowTitle            = TEXT( "$$root$$" );
  164.     m_bUseDepthBuffer           = TRUE;
  165.  
  166. $$IF(D3DFONT)
  167.     // Create a D3D font using d3dfont.cpp
  168.     m_pFont                     = new CD3DFont( _T("Arial"), 12, D3DFONT_BOLD );
  169. $$ELSE
  170.     m_pD3DXFont                 = NULL;
  171. $$ENDIF
  172.     m_bLoadingApp               = TRUE;
  173. $$IF(SHOW_TRIANGLE)
  174.     m_pVB                       = NULL;
  175. $$ENDIF
  176. $$IF(SHOW_TEAPOT)
  177.     m_pD3DXMesh                 = NULL;
  178. $$ENDIF
  179. $$IF(KEYBOARD)
  180.     m_pDI                       = NULL;
  181.     m_pKeyboard                 = NULL;
  182. $$ENDIF
  183. $$IF(ACTIONMAPPER)
  184.     m_pInputDeviceManager       = NULL;
  185. $$ENDIF
  186. $$IF(DMUSIC || DSOUND)
  187. $$IF(DMUSIC)
  188.     m_pMusicManager             = NULL;
  189.     m_pBounceSound              = NULL;
  190. $$ELSE
  191.     m_pSoundManager             = NULL;
  192.     m_pBounceSound              = NULL;
  193. $$ENDIF
  194. $$ENDIF
  195. $$IF(ACTIONMAPPER)
  196.     m_pDIConfigSurface          = NULL;
  197. $$ENDIF
  198.  
  199.     ZeroMemory( &m_UserInput, sizeof(m_UserInput) );
  200.     m_fWorldRotX                = 0.0f;
  201.     m_fWorldRotY                = 0.0f;
  202. $$IF(DPLAY)
  203.  
  204.     m_pDP                       = NULL;    
  205.     m_pNetConnectWizard         = NULL;    
  206.     m_pLobbiedApp               = NULL;    
  207.     m_bWasLobbyLaunched         = FALSE;   
  208.     m_dpnidLocalPlayer          = 0;       
  209.     m_lNumberOfActivePlayers    = 0;       
  210.     m_pLocalPlayerInfo          = NULL;
  211.     m_hrNet                     = S_OK;
  212.     m_fWorldSyncTimer           = 0.0f;
  213.     m_bHostPausing              = FALSE;
  214.  
  215.     ZeroMemory( &m_PlayInfoList, sizeof(APP_PLAYER_INFO) );
  216.     m_PlayInfoList.pNext = &m_PlayInfoList;
  217.     m_PlayInfoList.pPrev = &m_PlayInfoList;
  218. $$ENDIF
  219. $$IF(DPLAYVOICE)
  220.  
  221.     m_pNetVoice                 = NULL;
  222. $$ENDIF
  223.  
  224.     // Read settings from registry
  225.     ReadSettings();
  226. }
  227.  
  228.  
  229.  
  230.  
  231. //-----------------------------------------------------------------------------
  232. // Name: OneTimeSceneInit()
  233. // Desc: Called during initial app startup, this function performs all the
  234. //       permanent initialization.
  235. //-----------------------------------------------------------------------------
  236. HRESULT CMyD3DApplication::OneTimeSceneInit()
  237. {
  238.     // TODO: perform one time initialization
  239.  
  240.     // Drawing loading status message until app finishes loading
  241.     SendMessage( m_hWnd, WM_PAINT, 0, 0 );
  242.  
  243. $$IF(DPLAY)
  244.     // Init COM so we can use CoCreateInstance.  And be sure to init 
  245.     // COM as multithreaded when using DirectPlay
  246.     HRESULT hr;
  247.     if( FAILED( hr = CoInitializeEx( NULL, COINIT_MULTITHREADED ) ) )
  248.         return hr;
  249.  
  250. $$ENDIF
  251. $$IF(DINPUT)
  252.     // Initialize DirectInput
  253.     InitInput( m_hWnd );
  254.  
  255. $$ENDIF
  256. $$IF(DMUSIC || DSOUND)
  257.     // Initialize audio
  258.     InitAudio( m_hWnd );
  259.  
  260. $$ENDIF
  261. $$IF(DPLAY)
  262.     // Initialize DirectPlay
  263.     InitDirectPlay();
  264.  
  265.     // Create a new DirectPlay session or join to an existing DirectPlay session
  266.     if( FAILED( hr = ConnectViaDirectPlay() ) )
  267.         return hr;
  268.  
  269. $$ENDIF
  270.     m_bLoadingApp = FALSE;
  271.  
  272.     return S_OK;
  273. }
  274.  
  275.  
  276.  
  277.  
  278. //-----------------------------------------------------------------------------
  279. // Name: ReadSettings()
  280. // Desc: Read the app settings from the registry
  281. //-----------------------------------------------------------------------------
  282. VOID CMyD3DApplication::ReadSettings()
  283. {
  284.     HKEY hkey;
  285.     if( ERROR_SUCCESS == RegCreateKeyEx( HKEY_CURRENT_USER, DXAPP_KEY, 
  286.         0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL ) )
  287.     {
  288.         // TODO: change as needed
  289.  
  290.         // Read the stored window width/height.  This is just an example,
  291.         // of how to use DXUtil_Read*() functions.
  292.         DXUtil_ReadIntRegKey( hkey, TEXT("Width"), &m_dwCreationWidth, m_dwCreationWidth );
  293.         DXUtil_ReadIntRegKey( hkey, TEXT("Height"), &m_dwCreationHeight, m_dwCreationHeight );
  294.  
  295. $$IF(DPLAY)
  296.         // Read the saved strings needed by DirectPlay
  297.         DXUtil_ReadStringRegKey( hkey, TEXT("Player Name"), 
  298.                                  m_strLocalPlayerName, MAX_PATH, TEXT("$$root$$ Player") );
  299.         DXUtil_ReadStringRegKey( hkey, TEXT("Session Name"), 
  300.                                  m_strSessionName, MAX_PATH, TEXT("$$root$$ Game") );
  301.         DXUtil_ReadStringRegKey( hkey, TEXT("Preferred Provider"), 
  302.                                  m_strPreferredProvider, MAX_PATH, 
  303.                                  TEXT("DirectPlay8 TCP/IP Service Provider") );
  304.  
  305. $$ENDIF
  306.         RegCloseKey( hkey );
  307.     }
  308. }
  309.  
  310.  
  311.  
  312.  
  313. //-----------------------------------------------------------------------------
  314. // Name: WriteSettings()
  315. // Desc: Write the app settings to the registry
  316. //-----------------------------------------------------------------------------
  317. VOID CMyD3DApplication::WriteSettings()
  318. {
  319.     HKEY hkey;
  320.     DWORD dwType = REG_DWORD;
  321.     DWORD dwLength = sizeof(DWORD);
  322.  
  323.     if( ERROR_SUCCESS == RegCreateKeyEx( HKEY_CURRENT_USER, DXAPP_KEY, 
  324.         0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL ) )
  325.     {
  326.         // TODO: change as needed
  327.  
  328.         // Write the window width/height.  This is just an example,
  329.         // of how to use DXUtil_Write*() functions.
  330.         DXUtil_WriteIntRegKey( hkey, TEXT("Width"), m_rcWindowClient.right );
  331.         DXUtil_WriteIntRegKey( hkey, TEXT("Height"), m_rcWindowClient.bottom );
  332.  
  333. $$IF(DPLAY)
  334.         // Save the strings used by DirectPlay that were entered via the UI
  335.         DXUtil_WriteStringRegKey( hkey, TEXT("Player Name"), m_strLocalPlayerName );
  336.         DXUtil_WriteStringRegKey( hkey, TEXT("Session Name"), m_strSessionName );
  337.         DXUtil_WriteStringRegKey( hkey, TEXT("Preferred Provider"), m_strPreferredProvider );
  338.         
  339. $$ENDIF
  340.         RegCloseKey( hkey );
  341.     }
  342. }
  343.  
  344.  
  345.  
  346.  
  347.  
  348. $$IF(ACTIONMAPPER)
  349. //-----------------------------------------------------------------------------
  350. // Name: StaticInputAddDeviceCB()
  351. // Desc: Static callback helper to call into CMyD3DApplication class
  352. //-----------------------------------------------------------------------------
  353. HRESULT CALLBACK CMyD3DApplication::StaticInputAddDeviceCB( 
  354.                                          CInputDeviceManager::DeviceInfo* pDeviceInfo, 
  355.                                          const DIDEVICEINSTANCE* pdidi, 
  356.                                          LPVOID pParam )
  357. {
  358.     CMyD3DApplication* pApp = (CMyD3DApplication*) pParam;
  359.     return pApp->InputAddDeviceCB( pDeviceInfo, pdidi );
  360. }
  361.  
  362.  
  363.  
  364.  
  365. //-----------------------------------------------------------------------------
  366. // Name: InputAddDeviceCB()
  367. // Desc: Called from CInputDeviceManager whenever a device is added. 
  368. //       Set the dead zone, and creates a new InputDeviceState for each device
  369. //-----------------------------------------------------------------------------
  370. HRESULT CMyD3DApplication::InputAddDeviceCB( CInputDeviceManager::DeviceInfo* pDeviceInfo, 
  371.                                                    const DIDEVICEINSTANCE* pdidi )
  372. {
  373.     // Setup the deadzone 
  374.     DIPROPDWORD dipdw;
  375.     dipdw.diph.dwSize       = sizeof(DIPROPDWORD);
  376.     dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
  377.     dipdw.diph.dwObj        = 0;
  378.     dipdw.diph.dwHow        = DIPH_DEVICE;
  379.     dipdw.dwData            = 500;
  380.     pDeviceInfo->pdidDevice->SetProperty( DIPROP_DEADZONE, &dipdw.diph );
  381.  
  382.     // Create a new InputDeviceState for each device so the 
  383.     // app can record its state 
  384.     InputDeviceState* pNewInputDeviceState = new InputDeviceState;
  385.     ZeroMemory( pNewInputDeviceState, sizeof(InputDeviceState) );
  386.     pDeviceInfo->pParam = (LPVOID) pNewInputDeviceState;
  387.  
  388.     return S_OK;
  389. }
  390.  
  391.  
  392.  
  393.  
  394. $$ENDIF
  395. $$IF(DINPUT)
  396. //-----------------------------------------------------------------------------
  397. // Name: InitInput()
  398. // Desc: Initialize DirectInput objects
  399. //-----------------------------------------------------------------------------
  400. HRESULT CMyD3DApplication::InitInput( HWND hWnd )
  401. {
  402.     HRESULT hr;
  403.  
  404. $$IF(KEYBOARD)
  405.     // Create a IDirectInput8*
  406.     if( FAILED( hr = DirectInput8Create( GetModuleHandle(NULL), DIRECTINPUT_VERSION, 
  407.                                          IID_IDirectInput8, (VOID**)&m_pDI, NULL ) ) )
  408.         return DXTRACE_ERR_NOMSGBOX( "DirectInput8Create", hr );
  409.     
  410.     // Create a IDirectInputDevice8* for the keyboard
  411.     if( FAILED( hr = m_pDI->CreateDevice( GUID_SysKeyboard, &m_pKeyboard, NULL ) ) )
  412.         return DXTRACE_ERR_NOMSGBOX( "CreateDevice", hr );
  413.     
  414.     // Set the keyboard data format
  415.     if( FAILED( hr = m_pKeyboard->SetDataFormat( &c_dfDIKeyboard ) ) )
  416.         return DXTRACE_ERR_NOMSGBOX( "SetDataFormat", hr );
  417.     
  418.     // Set the cooperative level on the keyboard
  419.     if( FAILED( hr = m_pKeyboard->SetCooperativeLevel( hWnd, 
  420.                                             DISCL_NONEXCLUSIVE | 
  421.                                             DISCL_FOREGROUND | 
  422.                                             DISCL_NOWINKEY ) ) )
  423.         return DXTRACE_ERR_NOMSGBOX( "SetCooperativeLevel", hr );
  424.  
  425.     // Acquire the keyboard
  426.     m_pKeyboard->Acquire();
  427. $$ENDIF
  428. $$IF(ACTIONMAPPER)
  429.     // Setup action format for the actual gameplay
  430.     ZeroMemory( &m_diafGame, sizeof(DIACTIONFORMAT) );
  431.     m_diafGame.dwSize          = sizeof(DIACTIONFORMAT);
  432.     m_diafGame.dwActionSize    = sizeof(DIACTION);
  433.     m_diafGame.dwDataSize      = NUMBER_OF_GAMEACTIONS * sizeof(DWORD);
  434.     m_diafGame.guidActionMap   = g_guidApp;
  435.  
  436.     // TODO: change the genre as needed
  437.     m_diafGame.dwGenre         = DIVIRTUAL_CAD_3DCONTROL; 
  438.  
  439.     m_diafGame.dwNumActions    = NUMBER_OF_GAMEACTIONS;
  440.     m_diafGame.rgoAction       = g_rgGameAction;
  441.     m_diafGame.lAxisMin        = -100;
  442.     m_diafGame.lAxisMax        = 100;
  443.     m_diafGame.dwBufferSize    = 16;
  444.     _tcscpy( m_diafGame.tszActionMap, _T("$$root$$ Game") );
  445.  
  446.     // Create a new input device manager
  447.     m_pInputDeviceManager = new CInputDeviceManager();
  448.  
  449.     if( FAILED( hr = m_pInputDeviceManager->Create( hWnd, NULL, m_diafGame, 
  450.                                                     StaticInputAddDeviceCB, this ) ) )
  451.         return DXTRACE_ERR_NOMSGBOX( "m_pInputDeviceManager->Create", hr );
  452. $$ENDIF
  453.  
  454.     return S_OK;
  455. }
  456.  
  457.  
  458.  
  459.  
  460. $$ENDIF
  461. $$IF(DMUSIC || DSOUND)
  462. //-----------------------------------------------------------------------------
  463. // Name: InitAudio()
  464. // Desc: Initialize DirectX audio objects
  465. //-----------------------------------------------------------------------------
  466. HRESULT CMyD3DApplication::InitAudio( HWND hWnd )
  467. {
  468.     HRESULT hr;
  469.  
  470. $$IF(DMUSIC)
  471.     // Create the music manager class, used to create the sounds
  472.     m_pMusicManager = new CMusicManager();
  473.     if( FAILED( hr = m_pMusicManager->Initialize( hWnd ) ) )
  474.         return DXTRACE_ERR_NOMSGBOX( "m_pMusicManager->Initialize", hr );
  475.  
  476.     // Instruct the music manager where to find the files
  477.     // TODO: Set this to the media directory, or use resources
  478.     TCHAR szPath[MAX_PATH];
  479.     GetCurrentDirectory( MAX_PATH, szPath ); 
  480.     m_pMusicManager->SetSearchDirectory( szPath );
  481.  
  482.     // TODO: load the sounds from resources (or files)
  483.     m_pMusicManager->CreateSegmentFromResource( &m_pBounceSound, _T("BOUNCE"), _T("WAVE") );
  484.  
  485. $$ELSE
  486.     // Create a static IDirectSound in the CSound class.  
  487.     // Set coop level to DSSCL_PRIORITY, and set primary buffer 
  488.     // format to stereo, 22kHz and 16-bit output.
  489.     m_pSoundManager = new CSoundManager();
  490.  
  491.     if( FAILED( hr = m_pSoundManager->Initialize( hWnd, DSSCL_PRIORITY, 2, 22050, 16 ) ) )
  492.         return DXTRACE_ERR_NOMSGBOX( TEXT("m_pSoundManager->Initialize"), hr );
  493.  
  494.     // TODO: load the sounds from resources (or files)
  495.     m_pSoundManager->Create( &m_pBounceSound, TEXT("BOUNCE"), 0, GUID_NULL, 5 );
  496.  
  497. $$ENDIF
  498.     return S_OK;
  499. }
  500.  
  501.  
  502.  
  503.  
  504. $$ENDIF
  505. $$IF(DPLAY)
  506. //-----------------------------------------------------------------------------
  507. // Name: InitDirectPlay()
  508. // Desc: Initialize DirectPlay
  509. //-----------------------------------------------------------------------------
  510. HRESULT CMyD3DApplication::InitDirectPlay()
  511. {
  512.     // Initialize critical sections
  513.     InitializeCriticalSection( &g_csPlayerContext );
  514.     InitializeCriticalSection( &g_csWorldStateContext );
  515.  
  516.     // Create helper class
  517.     m_pNetConnectWizard = new CNetConnectWizard( g_hInst, m_hWnd, 
  518.                                                  m_strWindowTitle, &g_guidApp );
  519. $$IF(DPLAYVOICE)
  520.     m_pNetVoice         = new CNetVoice( StaticDirectPlayVoiceClientMessageHandler, StaticDirectPlayVoiceServerMessageHandler );
  521. $$ENDIF
  522.  
  523.     DPNHANDLE hLobbyLaunchedConnection = NULL;
  524.     HRESULT hr;
  525.  
  526.     // Create IDirectPlay8Peer
  527.     if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8Peer, NULL, 
  528.                                        CLSCTX_INPROC_SERVER,
  529.                                        IID_IDirectPlay8Peer, 
  530.                                        (LPVOID*) &m_pDP ) ) )
  531.         return DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
  532.  
  533.     // Create IDirectPlay8LobbiedApplication
  534.     if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8LobbiedApplication, NULL, 
  535.                                        CLSCTX_INPROC_SERVER,
  536.                                        IID_IDirectPlay8LobbiedApplication, 
  537.                                        (LPVOID*) &m_pLobbiedApp ) ) )
  538.         return DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
  539.  
  540.     // Init the helper class, now that m_pDP and m_pLobbiedApp are valid
  541.     m_pNetConnectWizard->Init( m_pDP, m_pLobbiedApp );
  542.  
  543.     // Init IDirectPlay8Peer
  544.     if( FAILED( hr = m_pDP->Initialize( NULL, StaticDirectPlayMessageHandler, 0 ) ) )
  545.         return DXTRACE_ERR( TEXT("Initialize"), hr );
  546.  
  547.     // Init IDirectPlay8LobbiedApplication.  Before this Initialize() returns 
  548.     // a DPL_MSGID_CONNECT msg may come in to the DirectPlayLobbyMessageHandler 
  549.     // so be prepared ahead of time.
  550.     if( FAILED( hr = m_pLobbiedApp->Initialize( NULL, StaticDirectPlayLobbyMessageHandler, 
  551.                                                 &hLobbyLaunchedConnection, 0 ) ) )
  552.         return DXTRACE_ERR( TEXT("Initialize"), hr );
  553.  
  554.     // IDirectPlay8LobbiedApplication::Initialize returns a handle to a connection
  555.     // if we have been lobby launched.  Initialize is guaranteed to return after 
  556.     // the DPL_MSGID_CONNECT msg has been processed.  So unless a we are expected 
  557.     // multiple lobby connections, we do not need to remember the lobby connection
  558.     // handle since it will be recorded upon the DPL_MSGID_CONNECT msg.
  559.     m_bWasLobbyLaunched = ( hLobbyLaunchedConnection != NULL );
  560.  
  561.         return S_OK;
  562. }
  563.  
  564.  
  565.  
  566.  
  567. //-----------------------------------------------------------------------------
  568. // Name: ConnectViaDirectPlay()
  569. // Desc: Create a new DirectPlay session or join to an existing DirectPlay session
  570. //-----------------------------------------------------------------------------
  571. HRESULT CMyD3DApplication::ConnectViaDirectPlay()
  572. {
  573.     HRESULT hr;
  574.     BOOL bWasFullscreen  = FALSE;
  575.     BOOL bConnectSuccess = FALSE;
  576.  
  577.     // Can't display dialogs in fullscreen mode
  578.     if( m_bWindowed == FALSE )
  579.     {
  580.         bWasFullscreen = TRUE;
  581.  
  582.         if( FAILED( ToggleFullscreen() ) )
  583.         {
  584.             DisplayErrorMsg( D3DAPPERR_RESIZEFAILED, MSGERR_APPMUSTEXIT );
  585.             return E_FAIL;
  586.         }
  587.     }
  588.  
  589.     // If we were launched from a lobby client, then we may have connection settings
  590.     // that we can use either host or join a game.  If not, then we'll need to prompt 
  591.     // the user to determine how to connect.
  592.     if( m_bWasLobbyLaunched && m_pNetConnectWizard->HaveConnectionSettingsFromLobby() )
  593.     {
  594.         // If were lobby launched then the DPL_MSGID_CONNECT has already been
  595.         // handled, and since the lobby client also sent us connection settings
  596.         // we can use them to either host or join a DirectPlay session. 
  597.         if( FAILED( hr = m_pNetConnectWizard->ConnectUsingLobbySettings() ) )
  598.         {
  599.             DXTRACE_ERR( TEXT("ConnectUsingLobbySettings"), hr );
  600.             MessageBox( m_hWnd, TEXT("Failed to connect using lobby settings. ")
  601.                         TEXT("The sample will now quit."),
  602.                         TEXT("$$root$$"), MB_OK | MB_ICONERROR );
  603.  
  604.             bConnectSuccess = FALSE;
  605.         }
  606.         else
  607.         {
  608.             // Read information from m_pNetConnectWizard
  609.             _tcscpy( m_strLocalPlayerName, m_pNetConnectWizard->GetPlayerName() );
  610.  
  611.             bConnectSuccess = TRUE; 
  612.         }
  613.     }
  614.     else
  615.     {
  616.         // If not lobby launched, prompt the user about the network 
  617.         // connection and which session they would like to join or 
  618.         // if they want to create a new one.
  619.  
  620.         // Setup connection wizard
  621.         m_pNetConnectWizard->SetPlayerName( m_strLocalPlayerName );
  622.         m_pNetConnectWizard->SetSessionName( m_strSessionName );
  623.         m_pNetConnectWizard->SetPreferredProvider( m_strPreferredProvider );
  624.  
  625.         // Start a connection wizard.  The wizard uses GDI dialog boxes.
  626.         // More complex games can use this as a starting point and add a 
  627.         // fancier graphics layer such as Direct3D.
  628.         hr = m_pNetConnectWizard->DoConnectWizard( FALSE );        
  629.         if( FAILED( hr ) ) 
  630.         {
  631.             DXTRACE_ERR( TEXT("DoConnectWizard"), hr );
  632.             MessageBox( m_hWnd, TEXT("Multiplayer connect failed. ")
  633.                         TEXT("The sample will now quit."),
  634.                         TEXT("$$root$$"), MB_OK | MB_ICONERROR );
  635.             bConnectSuccess = FALSE;
  636.         } 
  637.         else if( hr == NCW_S_QUIT ) 
  638.         {
  639.             // The user canceled the Multiplayer connect
  640.             bConnectSuccess = FALSE;
  641.         }
  642.         else
  643.         {
  644.             bConnectSuccess = TRUE; 
  645.  
  646.             // Read information from m_pNetConnectWizard
  647.             _tcscpy( m_strLocalPlayerName, m_pNetConnectWizard->GetPlayerName() );
  648.             _tcscpy( m_strSessionName, m_pNetConnectWizard->GetSessionName() );
  649.             _tcscpy( m_strPreferredProvider, m_pNetConnectWizard->GetPreferredProvider() );
  650.  
  651.             // Write information to the registry
  652.             WriteSettings();
  653.         }
  654.     }
  655.  
  656. $$IF(DPLAYVOICE)
  657.     if( bConnectSuccess )
  658.     {
  659.         // Initialize DirectPlay voice
  660.         if( FAILED( hr = InitDirectPlayVoice() ) )
  661.         {
  662.             bConnectSuccess = FALSE;
  663.  
  664.             if( hr == DVERR_USERBACK )
  665.             {
  666.                 MessageBox( m_hWnd, TEXT("The user backed out of the wizard.  ")
  667.                             TEXT("This simple sample does not handle this case, so ")
  668.                             TEXT("the sample will quit."), TEXT("DirectPlay Sample"), MB_OK );
  669.             }
  670.             else if( hr == DVERR_USERCANCEL )
  671.             {
  672.                 MessageBox( m_hWnd, TEXT("The user canceled the wizard. ")
  673.                             TEXT("This simple sample does not handle this case, so ")
  674.                             TEXT("the sample will quit."), TEXT("DirectPlay Sample"), MB_OK );
  675.             }
  676.             else 
  677.             {
  678.                 DXTRACE_ERR( TEXT("m_pNetVoice->Init"), hr );
  679.             }
  680.         }
  681.  
  682.         if( m_pNetVoice->IsHalfDuplex() ) 
  683.         {
  684.             MessageBox( m_hWnd, TEXT("You are running in half duplex mode. ")
  685.                         TEXT("In half duplex mode no recording takes place."), 
  686.                         TEXT("blank"), MB_OK );
  687.         }
  688.     }
  689.  
  690. $$ENDIF
  691.     if( FALSE == bConnectSuccess )
  692.     {
  693.         // Quit the app
  694.         PostQuitMessage(0);
  695.     }
  696.     else
  697.     {
  698.         // Return to fullscreen mode after dialogs
  699.         if( bWasFullscreen )
  700.         {
  701.             if( FAILED( ToggleFullscreen() ) )
  702.             {
  703.                 DisplayErrorMsg( D3DAPPERR_RESIZEFAILED, MSGERR_APPMUSTEXIT );
  704.                 return E_FAIL;
  705.             }
  706.         }
  707.     }
  708.  
  709.     return S_OK;
  710. }
  711.  
  712.  
  713.  
  714.  
  715. $$ENDIF
  716. $$IF(DPLAYVOICE)
  717. //-----------------------------------------------------------------------------
  718. // Name: InitDirectPlayVoice()
  719. // Desc: Init DirectPlay Voice
  720. //-----------------------------------------------------------------------------
  721. HRESULT CMyD3DApplication::InitDirectPlayVoice()
  722. {
  723.     HRESULT hr;
  724.  
  725.     // Set default DirectPlayVoice setup options
  726.     // TODO: change as needed or ask user for settings
  727.     ZeroMemory( &m_dvClientConfig, sizeof(m_dvClientConfig) );
  728.     m_dvClientConfig.dwSize                 = sizeof(m_dvClientConfig);
  729.     m_dvClientConfig.dwFlags                = DVCLIENTCONFIG_AUTOVOICEACTIVATED |
  730.                                               DVCLIENTCONFIG_AUTORECORDVOLUME;
  731.     m_dvClientConfig.lPlaybackVolume        = DVPLAYBACKVOLUME_DEFAULT;
  732.     m_dvClientConfig.dwBufferQuality        = DVBUFFERQUALITY_DEFAULT;
  733.     m_dvClientConfig.dwBufferAggressiveness = DVBUFFERAGGRESSIVENESS_DEFAULT;
  734.     m_dvClientConfig.dwThreshold            = DVTHRESHOLD_UNUSED;
  735.     m_dvClientConfig.lRecordVolume          = DVRECORDVOLUME_LAST;
  736.     m_dvClientConfig.dwNotifyPeriod         = 0;
  737.  
  738.     m_guidDVSessionCT                       = DPVCTGUID_DEFAULT;
  739.  
  740.     // Creates and connects to DirectPlay Voice using the settings stored 
  741.     // in m_guidDVSessionCT & m_dvClientConfig.  It also runs the DirectPlay
  742.     // Voice wizard if it hasn't been run before on this machine
  743.     if( FAILED( hr = m_pNetVoice->Init( m_hWnd, m_pNetConnectWizard->IsHostPlayer(), TRUE,
  744.                                         m_pDP, DVSESSIONTYPE_PEER, 
  745.                                         &m_guidDVSessionCT, &m_dvClientConfig ) ) )
  746.         return hr;
  747.  
  748.     return S_OK;
  749. }
  750.  
  751.  
  752.  
  753.  
  754. $$ENDIF
  755. //-----------------------------------------------------------------------------
  756. // Name: ConfirmDevice()
  757. // Desc: Called during device initialization, this code checks the display device
  758. //       for some minimum set of capabilities
  759. //-----------------------------------------------------------------------------
  760. HRESULT CMyD3DApplication::ConfirmDevice( D3DCAPS8* pCaps, DWORD dwBehavior,
  761.                                           D3DFORMAT Format )
  762. {
  763.     BOOL bCapsAcceptable;
  764.  
  765.     // TODO: Perform checks to see if these display caps are acceptable.
  766.     bCapsAcceptable = TRUE;
  767.  
  768.     if( bCapsAcceptable )         
  769.         return S_OK;
  770.     else
  771.         return E_FAIL;
  772. }
  773.  
  774.  
  775.  
  776.  
  777. //-----------------------------------------------------------------------------
  778. // Name: InitDeviceObjects()
  779. // Desc: Initialize scene objects.
  780. //-----------------------------------------------------------------------------
  781. HRESULT CMyD3DApplication::InitDeviceObjects()
  782. {
  783.     // TODO: create device objects
  784.  
  785. $$IF(SHOW_TRIANGLE || SHOW_TEAPOT)
  786.     HRESULT hr;
  787.  
  788. $$ENDIF
  789. $$IF(D3DFONT)
  790.     // Init the font
  791.     m_pFont->InitDeviceObjects( m_pd3dDevice );
  792.  
  793. $$ENDIF
  794. $$IF(SHOW_TRIANGLE)
  795.     // Create the vertex buffer
  796.     if( FAILED( hr = m_pd3dDevice->CreateVertexBuffer( 3*2*sizeof(CUSTOMVERTEX),
  797.                                                   0, D3DFVF_CUSTOMVERTEX,
  798.                                                   D3DPOOL_MANAGED, &m_pVB ) ) )
  799.         return DXTRACE_ERR_NOMSGBOX( "CreateVertexBuffer", hr );
  800.  
  801.     // Fill the vertex buffer with 2 triangles
  802.     CUSTOMVERTEX* pVertices;
  803.  
  804.     if( FAILED( hr = m_pVB->Lock( 0, 0, (BYTE**)&pVertices, 0 ) ) )
  805.         return DXTRACE_ERR_NOMSGBOX( "Lock", hr );
  806.  
  807.     // Front triangle
  808.     pVertices[0].position = D3DXVECTOR3( -1.0f, -1.0f,  0.0f );
  809.     pVertices[0].normal   = D3DXVECTOR3(  0.0f,  0.0f, -1.0f );
  810.     pVertices[1].position = D3DXVECTOR3(  0.0f,  1.0f,  0.0f );
  811.     pVertices[1].normal   = D3DXVECTOR3(  0.0f,  0.0f, -1.0f );
  812.     pVertices[2].position = D3DXVECTOR3(  1.0f, -1.0f,  0.0f );
  813.     pVertices[2].normal   = D3DXVECTOR3(  0.0f,  0.0f, -1.0f );
  814.  
  815.     // Back triangle
  816.     pVertices[3].position = D3DXVECTOR3( -1.0f, -1.0f,  0.0f );
  817.     pVertices[3].normal   = D3DXVECTOR3(  0.0f,  0.0f,  1.0f );
  818.     pVertices[4].position = D3DXVECTOR3(  1.0f, -1.0f,  0.0f );
  819.     pVertices[4].normal   = D3DXVECTOR3(  0.0f,  0.0f,  1.0f );
  820.     pVertices[5].position = D3DXVECTOR3(  0.0f,  1.0f,  0.0f );
  821.     pVertices[5].normal   = D3DXVECTOR3(  0.0f,  0.0f,  1.0f );
  822.  
  823.     m_pVB->Unlock();
  824.  
  825. $$ENDIF
  826. $$IF(SHOW_TEAPOT)
  827.     // Create a teapot mesh using D3DX
  828.     if( FAILED( hr = D3DXCreateTeapot( m_pd3dDevice, &m_pD3DXMesh, NULL ) ) )
  829.         return DXTRACE_ERR_NOMSGBOX( "D3DXCreateTeapot", hr );
  830.  
  831. $$ENDIF
  832.     return S_OK;
  833. }
  834.  
  835.  
  836.  
  837.  
  838. //-----------------------------------------------------------------------------
  839. // Name: RestoreDeviceObjects()
  840. // Desc: Restores scene objects.
  841. //-----------------------------------------------------------------------------
  842. HRESULT CMyD3DApplication::RestoreDeviceObjects()
  843. {
  844.     // TODO: setup render states
  845. $$IF(!D3DFONT || ACTIONMAPPER)
  846.     HRESULT hr;
  847. $$ENDIF
  848.  
  849.     // Setup a material
  850.     D3DMATERIAL8 mtrl;
  851.     D3DUtil_InitMaterial( mtrl, 1.0f, 0.0f, 0.0f );
  852.     m_pd3dDevice->SetMaterial( &mtrl );
  853.  
  854.     // Set up the textures
  855.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_MODULATE );
  856.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
  857.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
  858.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
  859.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );
  860.  
  861.     // Set miscellaneous render states
  862.     m_pd3dDevice->SetRenderState( D3DRS_DITHERENABLE,   FALSE );
  863.     m_pd3dDevice->SetRenderState( D3DRS_SPECULARENABLE, FALSE );
  864.     m_pd3dDevice->SetRenderState( D3DRS_ZENABLE,        TRUE );
  865.     m_pd3dDevice->SetRenderState( D3DRS_AMBIENT,        0x000F0F0F );
  866.  
  867.     // Set the world matrix
  868.     D3DXMATRIX matIdentity;
  869.     D3DXMatrixIdentity( &matIdentity );
  870.     m_pd3dDevice->SetTransform( D3DTS_WORLD,  &matIdentity );
  871.  
  872.     // Set up our view matrix. A view matrix can be defined given an eye point,
  873.     // a point to lookat, and a direction for which way is up. Here, we set the
  874.     // eye five units back along the z-axis and up three units, look at the
  875.     // origin, and define "up" to be in the y-direction.
  876.     D3DXMATRIX matView;
  877.     D3DXVECTOR3 vFromPt   = D3DXVECTOR3( 0.0f, 0.0f, -5.0f );
  878.     D3DXVECTOR3 vLookatPt = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
  879.     D3DXVECTOR3 vUpVec    = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
  880.     D3DXMatrixLookAtLH( &matView, &vFromPt, &vLookatPt, &vUpVec );
  881.     m_pd3dDevice->SetTransform( D3DTS_VIEW, &matView );
  882.  
  883.     // Set the projection matrix
  884.     D3DXMATRIX matProj;
  885.     FLOAT fAspect = ((FLOAT)m_d3dsdBackBuffer.Width) / m_d3dsdBackBuffer.Height;
  886.     D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, fAspect, 1.0f, 100.0f );
  887.     m_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
  888.  
  889.     // Set up lighting states
  890.     D3DLIGHT8 light;
  891.     D3DUtil_InitLight( light, D3DLIGHT_DIRECTIONAL, -1.0f, -1.0f, 2.0f );
  892.     m_pd3dDevice->SetLight( 0, &light );
  893.     m_pd3dDevice->LightEnable( 0, TRUE );
  894.     m_pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE );
  895.  
  896. $$IF(D3DFONT)
  897.     // Restore the font
  898.     m_pFont->RestoreDeviceObjects();
  899. $$ELSE
  900.     // Create a D3D font using D3DX
  901.     HFONT hFont = CreateFont( 20, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE,
  902.                               ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
  903.                               ANTIALIASED_QUALITY, FF_DONTCARE, "Arial" );      
  904.     if( FAILED( hr = D3DXCreateFont( m_pd3dDevice, hFont, &m_pD3DXFont ) ) )
  905.         return DXTRACE_ERR_NOMSGBOX( "D3DXCreateFont", hr );
  906. $$ENDIF
  907. $$IF(ACTIONMAPPER)
  908.  
  909.     if( !m_bWindowed )
  910.     {
  911.         // Create a surface for configuring DInput devices
  912.         if( FAILED( hr = m_pd3dDevice->CreateImageSurface( 640, 480, 
  913.                                         m_d3dsdBackBuffer.Format, &m_pDIConfigSurface ) ) ) 
  914.             return DXTRACE_ERR_NOMSGBOX( "CreateImageSurface", hr );
  915.     }
  916. $$ENDIF
  917.  
  918.     return S_OK;
  919. }
  920.  
  921.  
  922.  
  923.  
  924. $$IF(ACTIONMAPPER)
  925. //-----------------------------------------------------------------------------
  926. // Name: StaticConfigureInputDevicesCB()
  927. // Desc: Static callback helper to call into CMyD3DApplication class
  928. //-----------------------------------------------------------------------------
  929. BOOL CALLBACK CMyD3DApplication::StaticConfigureInputDevicesCB( 
  930.                                             IUnknown* pUnknown, VOID* pUserData )
  931. {
  932.     CMyD3DApplication* pApp = (CMyD3DApplication*) pUserData;
  933.     return pApp->ConfigureInputDevicesCB( pUnknown );
  934. }
  935.  
  936.  
  937.  
  938.  
  939. //-----------------------------------------------------------------------------
  940. // Name: ConfigureInputDevicesCB()
  941. // Desc: Callback function for configuring input devices. This function is
  942. //       called in fullscreen modes, so that the input device configuration
  943. //       window can update the screen.
  944. //-----------------------------------------------------------------------------
  945. BOOL CMyD3DApplication::ConfigureInputDevicesCB( IUnknown* pUnknown )
  946. {
  947.     // Get access to the surface
  948.     LPDIRECT3DSURFACE8 pConfigSurface = NULL;
  949.     if( FAILED( pUnknown->QueryInterface( IID_IDirect3DSurface8,
  950.                                           (VOID**)&pConfigSurface ) ) )
  951.         return TRUE;
  952.  
  953.     // Render the scene, with the config surface blitted on top
  954.     Render();
  955.  
  956.     RECT  rcSrc;
  957.     SetRect( &rcSrc, 0, 0, 640, 480 );
  958.  
  959.     POINT ptDst;
  960.     ptDst.x = (m_d3dsdBackBuffer.Width-640)/2;
  961.     ptDst.y = (m_d3dsdBackBuffer.Height-480)/2;
  962.  
  963.     LPDIRECT3DSURFACE8 pBackBuffer;
  964.     m_pd3dDevice->GetBackBuffer( 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer );
  965.     m_pd3dDevice->CopyRects( pConfigSurface, &rcSrc, 1, pBackBuffer, &ptDst );
  966.     pBackBuffer->Release();
  967.  
  968.     // Present the backbuffer contents to the front buffer
  969.     m_pd3dDevice->Present( 0, 0, 0, 0 );
  970.  
  971.     // Release the surface
  972.     pConfigSurface->Release();
  973.  
  974.     return TRUE;
  975. }
  976.  
  977.  
  978.  
  979.  
  980. $$ENDIF
  981. //-----------------------------------------------------------------------------
  982. // Name: FrameMove()
  983. // Desc: Called once per frame, the call is the entry point for animating
  984. //       the scene.
  985. //-----------------------------------------------------------------------------
  986. HRESULT CMyD3DApplication::FrameMove()
  987. {
  988.     // TODO: update world
  989.  
  990.     // Update user input state
  991.     UpdateInput( &m_UserInput );
  992.  
  993. $$IF(DPLAY)
  994.     // Send local input to all network players if it changed
  995.     SendLocalInputIfChanged();
  996.  
  997.     if( m_pNetConnectWizard->IsHostPlayer() )
  998.     {
  999.         m_fWorldSyncTimer -= m_fElapsedTime;
  1000.         if( m_fWorldSyncTimer < 0.0f )
  1001.         {
  1002.             // If this player is the host and timer has expired
  1003.             // then reset timer and send the world state to all players
  1004.             m_fWorldSyncTimer = 0.1f;
  1005.             SendWorldStateToAll();
  1006.         }
  1007.     }
  1008.  
  1009. $$ENDIF
  1010. $$IF(ACTIONMAPPER)
  1011.     // Respond to input
  1012.     if( m_UserInput.bDoConfigureInput )
  1013.     {
  1014.         // One-shot per keypress
  1015.         m_UserInput.bDoConfigureInput = FALSE;
  1016.  
  1017.         Pause( TRUE );
  1018.  
  1019.         // Get access to the list of semantically-mapped input devices
  1020.         // to delete all InputDeviceState structs before calling ConfigureDevices()
  1021.         CInputDeviceManager::DeviceInfo* pDeviceInfos;
  1022.         DWORD dwNumDevices;
  1023.         m_pInputDeviceManager->GetDevices( &pDeviceInfos, &dwNumDevices );
  1024.  
  1025.         for( DWORD i=0; i<dwNumDevices; i++ )
  1026.         {
  1027.             InputDeviceState* pInputDeviceState = (InputDeviceState*) pDeviceInfos[i].pParam;
  1028.             SAFE_DELETE( pInputDeviceState );
  1029.             pDeviceInfos[i].pParam = NULL;
  1030.         }
  1031.  
  1032.         // Configure the devices (with edit capability)
  1033.         if( m_bWindowed )
  1034.             m_pInputDeviceManager->ConfigureDevices( m_hWnd, NULL, NULL, DICD_EDIT, NULL );
  1035.         else
  1036.             m_pInputDeviceManager->ConfigureDevices( m_hWnd,
  1037.                                                      m_pDIConfigSurface,
  1038.                                                      (VOID*)StaticConfigureInputDevicesCB,
  1039.                                                      DICD_EDIT, (LPVOID) this );
  1040.  
  1041.         Pause( FALSE );
  1042.     }
  1043.  
  1044.     if( m_UserInput.bDoConfigureDisplay )
  1045.     {
  1046.         // One-shot per keypress
  1047.         m_UserInput.bDoConfigureDisplay = FALSE;
  1048.  
  1049.         Pause(TRUE);
  1050.  
  1051.         // Configure the display device
  1052.         UserSelectNewDevice();
  1053.  
  1054.         Pause(FALSE);
  1055.     }
  1056.  
  1057. $$ENDIF
  1058. $$IF(DPLAYVOICE)
  1059.     if( m_UserInput.bDoConfigureVoice )
  1060.     {
  1061.         // One-shot per keypress
  1062.         m_UserInput.bDoConfigureVoice = FALSE;
  1063.  
  1064.         Pause(TRUE);
  1065.  
  1066.         // Allow user to configure the voice settings
  1067.         UserConfigVoice();
  1068.  
  1069.         Pause(FALSE);
  1070.     }
  1071.  
  1072. $$ENDIF
  1073. $$IF(DPLAY)
  1074.     // Combining the input data from all players 
  1075.     // TODO: Combining the input data from all players is an unrealistic yet simple 
  1076.     //       usage of network data. Use it as a starting point to serve your needs
  1077.     CombineInputFromAllPlayers( &m_CombinedNetworkInput );
  1078.  
  1079. $$ENDIF
  1080. $$IF(DPLAYVOICE)
  1081.     // Update talking varibles 
  1082.     // TODO: The talking variables just update the text, but something more complex
  1083.     //       like animation could be done based on them
  1084.     UpdateTalkingVariables();
  1085.  
  1086. $$ENDIF
  1087.     // Update the world state according to user input
  1088.     D3DXMATRIX matWorld;
  1089.     D3DXMATRIX matRotY;
  1090.     D3DXMATRIX matRotX;
  1091.  
  1092. $$IF(DPLAY)
  1093.     // Enter world state critical section before accessing world state data 
  1094.     // otherwise one of the DirectPlay threads may change the data
  1095.     // while this thread is accessing or changing it.
  1096.     WORLD_LOCK();
  1097.  
  1098.     // Rotate object according to user input from all network players
  1099.     // Only update the world state if the host hasn't told our to pause
  1100.     if( FALSE == m_bHostPausing )
  1101.     {
  1102.         // Update the m_fWorldRotY & m_fWorldRotX according 
  1103.         // to the combined input of all the network players
  1104. $$IF(ACTIONMAPPER)
  1105.         if( m_CombinedNetworkInput.fAxisRotateLR )
  1106.             m_fWorldRotY += m_fElapsedTime * m_CombinedNetworkInput.fAxisRotateLR;
  1107.  
  1108.         if( m_CombinedNetworkInput.fAxisRotateUD )
  1109.             m_fWorldRotX += m_fElapsedTime * m_CombinedNetworkInput.fAxisRotateUD;
  1110. $$ELSE // start !ACTIONMAPPER
  1111.         if( m_CombinedNetworkInput.bRotateLeft && !m_CombinedNetworkInput.bRotateRight )
  1112.             m_fWorldRotY += m_fElapsedTime;
  1113.         else if( m_CombinedNetworkInput.bRotateRight && !m_CombinedNetworkInput.bRotateLeft )
  1114.             m_fWorldRotY -= m_fElapsedTime;
  1115.  
  1116.         if( m_CombinedNetworkInput.bRotateUp && !m_CombinedNetworkInput.bRotateDown )
  1117.             m_fWorldRotX += m_fElapsedTime;
  1118.         else if( m_CombinedNetworkInput.bRotateDown && !m_CombinedNetworkInput.bRotateUp )
  1119.             m_fWorldRotX -= m_fElapsedTime;
  1120. $$ENDIF // end ACTIONMAPPER
  1121.     }
  1122.  
  1123.     // Calculate and update the world matrix
  1124.     D3DXMatrixRotationX( &matRotX, m_fWorldRotX );
  1125.     D3DXMatrixRotationY( &matRotY, m_fWorldRotY );
  1126.  
  1127.     // Leave the critical section
  1128.     WORLD_UNLOCK();
  1129.  
  1130. $$ENDIF // end DPLAY
  1131. $$IF(!DPLAY)
  1132. $$IF(ACTIONMAPPER)
  1133.     if( m_UserInput.fAxisRotateLR )
  1134.         m_fWorldRotY += m_fElapsedTime * m_UserInput.fAxisRotateLR;
  1135.  
  1136.     if( m_UserInput.fAxisRotateUD )
  1137.         m_fWorldRotX += m_fElapsedTime * m_UserInput.fAxisRotateUD;
  1138.  
  1139. $$ELSE // start !ACTIONMAPPER
  1140.     if( m_UserInput.bRotateLeft && !m_UserInput.bRotateRight )
  1141.         m_fWorldRotY += m_fElapsedTime;
  1142.     else if( m_UserInput.bRotateRight && !m_UserInput.bRotateLeft )
  1143.         m_fWorldRotY -= m_fElapsedTime;
  1144.  
  1145.     if( m_UserInput.bRotateUp && !m_UserInput.bRotateDown )
  1146.         m_fWorldRotX += m_fElapsedTime;
  1147.     else if( m_UserInput.bRotateDown && !m_UserInput.bRotateUp )
  1148.         m_fWorldRotX -= m_fElapsedTime;
  1149.  
  1150. $$ENDIF // end ACTIONMAPPER
  1151.     D3DXMatrixRotationX( &matRotX, m_fWorldRotX );
  1152.     D3DXMatrixRotationY( &matRotY, m_fWorldRotY );
  1153.  
  1154. $$ENDIF // end !DPLAY
  1155.     D3DXMatrixMultiply( &matWorld, &matRotX, &matRotY );
  1156.     m_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
  1157.  
  1158. $$IF(DMUSIC || DSOUND)
  1159.     // Play the sound every so often while the button is pressed 
  1160.     if( m_UserInput.bPlaySoundButtonDown )
  1161.     {
  1162.         m_fSoundPlayRepeatCountdown -= m_fElapsedTime;
  1163.         if( m_fSoundPlayRepeatCountdown <= 0.0f )
  1164.         {
  1165.             m_fSoundPlayRepeatCountdown = 0.5f;
  1166.             if( m_pBounceSound )
  1167.                 m_pBounceSound->Play();
  1168.         }
  1169.     }
  1170.     else
  1171.     {
  1172.         m_fSoundPlayRepeatCountdown = 0.0f;
  1173.     }
  1174.  
  1175. $$ENDIF
  1176.     return S_OK;
  1177. }
  1178.  
  1179.  
  1180.  
  1181.  
  1182. //-----------------------------------------------------------------------------
  1183. // Name: UpdateInput()
  1184. // Desc: Update the user input.  Called once per frame 
  1185. //-----------------------------------------------------------------------------
  1186. void CMyD3DApplication::UpdateInput( UserInput* pUserInput )
  1187. {
  1188. $$IF(ACTIONMAPPER)
  1189.     if( NULL == m_pInputDeviceManager )
  1190.         return;
  1191.  
  1192.     // Get access to the list of semantically-mapped input devices
  1193.     CInputDeviceManager::DeviceInfo* pDeviceInfos;
  1194.     DWORD dwNumDevices;
  1195.     m_pInputDeviceManager->GetDevices( &pDeviceInfos, &dwNumDevices );
  1196.  
  1197.     // Loop through all devices and check game input
  1198.     for( DWORD i=0; i<dwNumDevices; i++ )
  1199.     {
  1200.         DIDEVICEOBJECTDATA rgdod[10];
  1201.         DWORD   dwItems = 10;
  1202.         HRESULT hr;
  1203.         LPDIRECTINPUTDEVICE8 pdidDevice = pDeviceInfos[i].pdidDevice;
  1204.         InputDeviceState* pInputDeviceState = (InputDeviceState*) pDeviceInfos[i].pParam;
  1205.  
  1206.         hr = pdidDevice->Acquire();
  1207.         hr = pdidDevice->Poll();
  1208.         hr = pdidDevice->GetDeviceData( sizeof(DIDEVICEOBJECTDATA),
  1209.                                         rgdod, &dwItems, 0 );
  1210.         if( FAILED(hr) )
  1211.             continue;
  1212.  
  1213.         // Get the sematics codes for the game menu
  1214.         for( DWORD j=0; j<dwItems; j++ )
  1215.         {
  1216.             BOOL  bButtonState = (rgdod[j].dwData==0x80) ? TRUE : FALSE;
  1217.             FLOAT fButtonState = (rgdod[j].dwData==0x80) ? 1.0f : 0.0f;
  1218.             FLOAT fAxisState   = (FLOAT)((int)rgdod[j].dwData)/100.0f;
  1219.  
  1220.             switch( rgdod[j].uAppData )
  1221.             {
  1222.                 // TODO: Handle semantics for the game 
  1223.  
  1224.                 // Handle relative axis data
  1225.                 case INPUT_ROTATE_AXIS_LR: 
  1226.                     pInputDeviceState->fAxisRotateLR = -fAxisState;
  1227.                     break;
  1228.                 case INPUT_ROTATE_AXIS_UD:
  1229.                     pInputDeviceState->fAxisRotateUD = -fAxisState;
  1230.                     break;
  1231.  
  1232.                 // Handle buttons separately so the button state data
  1233.                 // doesn't overwrite the axis state data, and handle
  1234.                 // each button separately so they don't overwrite each other
  1235.                 case INPUT_ROTATE_LEFT:  pInputDeviceState->bButtonRotateLeft  = bButtonState; break;
  1236.                 case INPUT_ROTATE_RIGHT: pInputDeviceState->bButtonRotateRight = bButtonState; break;
  1237.                 case INPUT_ROTATE_UP:    pInputDeviceState->bButtonRotateUp    = bButtonState; break;
  1238.                 case INPUT_ROTATE_DOWN:  pInputDeviceState->bButtonRotateDown  = bButtonState; break;
  1239. $$IF(DMUSIC || DSOUND)
  1240.                 case INPUT_PLAY_SOUND:   pInputDeviceState->bButtonPlaySoundButtonDown = bButtonState; break;
  1241. $$ENDIF // DMUSIC || DSOUND
  1242.  
  1243.                 // Handle one-shot buttons
  1244.                 case INPUT_CONFIG_INPUT:   if( bButtonState ) pUserInput->bDoConfigureInput = TRUE; break;
  1245.                 case INPUT_CONFIG_DISPLAY: if( bButtonState ) pUserInput->bDoConfigureDisplay = TRUE; break;
  1246. $$IF(DPLAYVOICE)
  1247.                 case INPUT_CONFIG_VOICE:   if( bButtonState ) pUserInput->bDoConfigureVoice   = TRUE; break;
  1248. $$ENDIF
  1249.             }
  1250.         }
  1251.     }
  1252.  
  1253.     // TODO: change process code as needed
  1254.  
  1255.     // Process user input and store result into pUserInput struct
  1256.     pUserInput->fAxisRotateLR = 0.0f;
  1257.     pUserInput->fAxisRotateUD = 0.0f;
  1258. $$IF(DMUSIC || DSOUND)
  1259.     pUserInput->bPlaySoundButtonDown = FALSE;
  1260. $$ENDIF
  1261.  
  1262.     // Concatinate the data from all the DirectInput devices
  1263.     for( i=0; i<dwNumDevices; i++ )
  1264.     {
  1265.         InputDeviceState* pInputDeviceState = (InputDeviceState*) pDeviceInfos[i].pParam;
  1266.  
  1267.         // Use the axis data that is furthest from zero
  1268.         if( fabs(pInputDeviceState->fAxisRotateLR) > fabs(pUserInput->fAxisRotateLR) )
  1269.             pUserInput->fAxisRotateLR = pInputDeviceState->fAxisRotateLR;
  1270.  
  1271.         if( fabs(pInputDeviceState->fAxisRotateUD) > fabs(pUserInput->fAxisRotateUD) )
  1272.             pUserInput->fAxisRotateUD = pInputDeviceState->fAxisRotateUD;
  1273.  
  1274.         // Process the button data 
  1275.         if( pInputDeviceState->bButtonRotateLeft )
  1276.             pUserInput->fAxisRotateLR = 1.0f;
  1277.         else if( pInputDeviceState->bButtonRotateRight )
  1278.             pUserInput->fAxisRotateLR = -1.0f;
  1279.  
  1280.         if( pInputDeviceState->bButtonRotateUp )
  1281.             pUserInput->fAxisRotateUD = 1.0f;
  1282.         else if( pInputDeviceState->bButtonRotateDown )
  1283.             pUserInput->fAxisRotateUD = -1.0f;
  1284.  
  1285. $$IF(DMUSIC || DSOUND)
  1286.         if( pInputDeviceState->bButtonPlaySoundButtonDown )
  1287.             pUserInput->bPlaySoundButtonDown = TRUE;
  1288. $$ENDIF // DMUSIC || DSOUND
  1289.     } 
  1290. $$ENDIF // ACTIONMAPPER
  1291. $$IF(KEYBOARD)
  1292.     HRESULT hr;
  1293.  
  1294.     // Get the input's device state, and put the state in dims
  1295.     ZeroMemory( &pUserInput->diks, sizeof(pUserInput->diks) );
  1296.     hr = m_pKeyboard->GetDeviceState( sizeof(pUserInput->diks), &pUserInput->diks );
  1297.     if( FAILED(hr) ) 
  1298.     {
  1299.         m_pKeyboard->Acquire();
  1300.         return; 
  1301.     }
  1302.  
  1303.     // TODO: Process user input as needed
  1304.     pUserInput->bRotateLeft  = ( (pUserInput->diks[DIK_LEFT] & 0x80)  == 0x80 );
  1305.     pUserInput->bRotateRight = ( (pUserInput->diks[DIK_RIGHT] & 0x80) == 0x80 );
  1306.     pUserInput->bRotateUp    = ( (pUserInput->diks[DIK_UP] & 0x80)    == 0x80 );
  1307.     pUserInput->bRotateDown  = ( (pUserInput->diks[DIK_DOWN] & 0x80)  == 0x80 );
  1308. $$IF(DMUSIC || DSOUND)
  1309.     pUserInput->bPlaySoundButtonDown   = ( (pUserInput->diks[DIK_F5] & 0x80)     == 0x80 );
  1310. $$ENDIF // DMUSIC || DSOUND
  1311. $$ENDIF // KEYBOARD
  1312. $$IF(!DINPUT)
  1313.     pUserInput->bRotateUp    = ( m_bHasFocus && (GetAsyncKeyState( VK_UP )    & 0x8000) == 0x8000 );
  1314.     pUserInput->bRotateDown  = ( m_bHasFocus && (GetAsyncKeyState( VK_DOWN )  & 0x8000) == 0x8000 );
  1315.     pUserInput->bRotateLeft  = ( m_bHasFocus && (GetAsyncKeyState( VK_LEFT )  & 0x8000) == 0x8000 );
  1316.     pUserInput->bRotateRight = ( m_bHasFocus && (GetAsyncKeyState( VK_RIGHT ) & 0x8000) == 0x8000 );
  1317. $$IF(DMUSIC || DSOUND)
  1318.     pUserInput->bPlaySoundButtonDown = ( m_bHasFocus && (GetAsyncKeyState( VK_F5 ) & 0x8000) == 0x8000 );
  1319. $$ENDIF // DMUSIC || DSOUND
  1320. $$ENDIF // !DINPUT
  1321. }
  1322.  
  1323.  
  1324.  
  1325.  
  1326. $$IF(DPLAY)
  1327. //-----------------------------------------------------------------------------
  1328. // Name: SendLocalInputIfChanged()
  1329. // Desc: Send local input to all network players if it changed
  1330. //-----------------------------------------------------------------------------
  1331. HRESULT CMyD3DApplication::SendLocalInputIfChanged()
  1332. {
  1333.     if( NULL == m_pLocalPlayerInfo )
  1334.         return S_OK;
  1335.  
  1336.     // Enter player critical section before accessing player's state data 
  1337.     // otherwise the DirectPlay network threads may change the data
  1338.     // while this thread is accessing it.
  1339.     PLAYER_LOCK();                  
  1340.  
  1341.     // Compare the local input axis data from DirectInput against the 
  1342.     // state of the axis data stored in the local player's 
  1343.     // APP_PLAYER_INFO struct to see if input changed
  1344.     BOOL bLocalInputChanged = FALSE;
  1345. $$IF(ACTIONMAPPER)
  1346.     if( m_UserInput.fAxisRotateLR != m_pLocalPlayerInfo->fAxisRotateLR ||
  1347.         m_UserInput.fAxisRotateUD != m_pLocalPlayerInfo->fAxisRotateUD )
  1348. $$ELSE
  1349.     if( m_UserInput.bRotateUp    != m_pLocalPlayerInfo->bRotateUp   ||
  1350.         m_UserInput.bRotateDown  != m_pLocalPlayerInfo->bRotateDown ||
  1351.         m_UserInput.bRotateLeft  != m_pLocalPlayerInfo->bRotateLeft ||
  1352.         m_UserInput.bRotateRight != m_pLocalPlayerInfo->bRotateRight )
  1353. $$ENDIF
  1354.     {
  1355.         bLocalInputChanged = TRUE;
  1356.     }
  1357.  
  1358.     PLAYER_UNLOCK();                // leave player context CS
  1359.  
  1360.     // If it has changed then send it to all the network players
  1361.     // including the local player
  1362.     if( bLocalInputChanged )
  1363.     {
  1364.         GAMEMSG_INPUTSTATE msgInputState;
  1365.         msgInputState.nType = GAME_MSGID_INPUTSTATE;
  1366. $$IF(ACTIONMAPPER)
  1367.         msgInputState.fAxisRotateLR = m_UserInput.fAxisRotateLR;
  1368.         msgInputState.fAxisRotateUD = m_UserInput.fAxisRotateUD;
  1369. $$ELSE
  1370.         msgInputState.bRotateUp    = m_UserInput.bRotateUp;
  1371.         msgInputState.bRotateDown  = m_UserInput.bRotateDown;
  1372.         msgInputState.bRotateLeft  = m_UserInput.bRotateLeft;
  1373.         msgInputState.bRotateRight = m_UserInput.bRotateRight;
  1374. $$ENDIF
  1375.  
  1376.         DPN_BUFFER_DESC bufferDesc;
  1377.         bufferDesc.dwBufferSize = sizeof(GAMEMSG_INPUTSTATE);
  1378.         bufferDesc.pBufferData  = (BYTE*) &msgInputState;
  1379.  
  1380.         // Send it to all of the players including the local client
  1381.         // DirectPlay will tell via the message handler 
  1382.         // if there are any severe errors, so ignore any errors 
  1383.         DPNHANDLE hAsync;
  1384.         m_pDP->SendTo( DPNID_ALL_PLAYERS_GROUP, &bufferDesc, 1,
  1385.                        0, NULL, &hAsync, DPNSEND_GUARANTEED );
  1386.     }
  1387.  
  1388.  
  1389.     return S_OK;
  1390. }
  1391.  
  1392.  
  1393.  
  1394.  
  1395. //-----------------------------------------------------------------------------
  1396. // Name: SendWorldStateToAll()
  1397. // Desc: Send the world state to all players on the network
  1398. //-----------------------------------------------------------------------------
  1399. HRESULT CMyD3DApplication::SendWorldStateToAll()
  1400. {
  1401.     // Enter world state critical section before accessing world state data 
  1402.     // otherwise one of the DirectPlay threads may change the data
  1403.     // while this thread is accessing it.
  1404.     WORLD_LOCK();
  1405.  
  1406.     GAMEMSG_WORLDSTATE msgWorldState;
  1407.     msgWorldState.nType = GAME_MSGID_WORLDSTATE;
  1408.     msgWorldState.fWorldRotX = m_fWorldRotX;
  1409.     msgWorldState.fWorldRotY = m_fWorldRotY;
  1410.  
  1411.     // Leave the critical section
  1412.     WORLD_UNLOCK();
  1413.  
  1414.     DPN_BUFFER_DESC bufferDesc;
  1415.     bufferDesc.dwBufferSize = sizeof(GAMEMSG_WORLDSTATE);
  1416.     bufferDesc.pBufferData  = (BYTE*) &msgWorldState;
  1417.  
  1418.     // Send the message to all the players except the ourselves
  1419.     // DirectPlay will tell via the message handler 
  1420.     // if there are any severe errors, so ignore any errors 
  1421.     DPNHANDLE hAsync;
  1422.     m_pDP->SendTo( DPNID_ALL_PLAYERS_GROUP, &bufferDesc, 1,
  1423.                    0, NULL, &hAsync, DPNSEND_NOLOOPBACK );
  1424.  
  1425.     return S_OK;
  1426. }
  1427.  
  1428.  
  1429.  
  1430.  
  1431. //-----------------------------------------------------------------------------
  1432. // Name: SendPauseMessageToAll()
  1433. // Desc: Send a pause message to all players on the network
  1434. //-----------------------------------------------------------------------------
  1435. HRESULT CMyD3DApplication::SendPauseMessageToAll( BOOL bPause )
  1436. {
  1437.     GAMEMSG_HOSTPAUSE msgPause;
  1438.     msgPause.nType = GAME_MSGID_HOSTPAUSE;
  1439.     msgPause.bHostPause = bPause; 
  1440.  
  1441.     DPN_BUFFER_DESC bufferDesc;
  1442.     bufferDesc.dwBufferSize = sizeof(GAMEMSG_HOSTPAUSE);
  1443.     bufferDesc.pBufferData  = (BYTE*) &msgPause;
  1444.  
  1445.     // Send the message to all the players except the ourselves
  1446.     // DirectPlay will tell via the message handler 
  1447.     // if there are any severe errors, so ignore any errors 
  1448.     DPNHANDLE hAsync;
  1449.     m_pDP->SendTo( DPNID_ALL_PLAYERS_GROUP, &bufferDesc, 1,
  1450.                    0, NULL, &hAsync, DPNSEND_GUARANTEED | DPNSEND_NOLOOPBACK );
  1451.  
  1452.     return S_OK;
  1453. }
  1454.  
  1455.  
  1456.  
  1457.  
  1458. $$IF(ACTIONMAPPER)
  1459. //-----------------------------------------------------------------------------
  1460. // Name: CombineInputFromAllPlayers()
  1461. // Desc: Combine axis input from all network players
  1462. //-----------------------------------------------------------------------------
  1463. HRESULT CMyD3DApplication::CombineInputFromAllPlayers( UserInput* pCombinedUserInput )
  1464. {
  1465.     FLOAT fAxisRotateLRCombined = 0.0f;
  1466.     FLOAT fAxisRotateUDCombined = 0.0f;
  1467.  
  1468.     // Enter player context CS before accessing APP_PLAYER_INFO structs
  1469.     // otherwise one of the DirectPlay threads may delete the struct
  1470.     // while this thread is accessing it.
  1471.     PLAYER_LOCK();                  
  1472.  
  1473.     APP_PLAYER_INFO* pPlayerInfo = m_PlayInfoList.pNext;
  1474.  
  1475.     while( pPlayerInfo != &m_PlayInfoList )
  1476.     {
  1477.         // Use the player whose axis data that is furthest from zero
  1478.         // and if one player is at -1, and another is at +1 then always
  1479.         // choose the positive one.
  1480.         if( fabs(pPlayerInfo->fAxisRotateLR) == fabs(fAxisRotateLRCombined) &&
  1481.                 pPlayerInfo->fAxisRotateLR > 0.0f )
  1482.             fAxisRotateLRCombined = pPlayerInfo->fAxisRotateLR;
  1483.         if( fabs(pPlayerInfo->fAxisRotateLR) > fabs(fAxisRotateLRCombined) )
  1484.             fAxisRotateLRCombined = pPlayerInfo->fAxisRotateLR;
  1485.  
  1486.         if( fabs(pPlayerInfo->fAxisRotateUD) == fabs(fAxisRotateUDCombined) && 
  1487.                 pPlayerInfo->fAxisRotateUD > 0.0f )
  1488.             fAxisRotateUDCombined = pPlayerInfo->fAxisRotateUD;
  1489.         if( fabs(pPlayerInfo->fAxisRotateUD) > fabs(fAxisRotateUDCombined) )
  1490.             fAxisRotateUDCombined = pPlayerInfo->fAxisRotateUD;
  1491.  
  1492.         pPlayerInfo = pPlayerInfo->pNext;
  1493.     }
  1494.  
  1495.     // Leave player context CS
  1496.     PLAYER_UNLOCK();           
  1497.     
  1498.     pCombinedUserInput->fAxisRotateLR = fAxisRotateLRCombined;
  1499.     pCombinedUserInput->fAxisRotateUD = fAxisRotateUDCombined;
  1500.  
  1501.     return S_OK;
  1502. }
  1503.  
  1504.  
  1505.  
  1506.  
  1507. $$ELSE // start !ACTIONMAPPER
  1508. //-----------------------------------------------------------------------------
  1509. // Name: CombineInputFromAllPlayers()
  1510. // Desc: Combine axis input from all network players
  1511. //-----------------------------------------------------------------------------
  1512. HRESULT CMyD3DApplication::CombineInputFromAllPlayers( UserInput* pCombinedUserInput )
  1513. {
  1514.     pCombinedUserInput->bRotateUp    = FALSE;
  1515.     pCombinedUserInput->bRotateDown  = FALSE;
  1516.     pCombinedUserInput->bRotateLeft  = FALSE;
  1517.     pCombinedUserInput->bRotateRight = FALSE;
  1518.  
  1519.     // Enter player context CS before accessing APP_PLAYER_INFO structs
  1520.     // otherwise one of the DirectPlay threads may delete the struct
  1521.     // while this thread is accessing it.
  1522.     PLAYER_LOCK();                  
  1523.  
  1524.     APP_PLAYER_INFO* pPlayerInfo = m_PlayInfoList.pNext;
  1525.  
  1526.     while( pPlayerInfo != &m_PlayInfoList )
  1527.     {
  1528.         // Use the player whose axis data that is furthest from zero
  1529.         // and if one player is at -1, and another is at +1 then always
  1530.         // choose the positive one.
  1531.         if( pPlayerInfo->bRotateUp )
  1532.             pCombinedUserInput->bRotateUp = TRUE;
  1533.         if( pPlayerInfo->bRotateDown )
  1534.             pCombinedUserInput->bRotateDown = TRUE;
  1535.         if( pPlayerInfo->bRotateLeft )
  1536.             pCombinedUserInput->bRotateLeft = TRUE;
  1537.         if( pPlayerInfo->bRotateRight )
  1538.             pCombinedUserInput->bRotateRight = TRUE;
  1539.  
  1540.         pPlayerInfo = pPlayerInfo->pNext;
  1541.     }
  1542.  
  1543.     // Leave player context CS
  1544.     PLAYER_UNLOCK();           
  1545.     
  1546.     return S_OK;
  1547. }
  1548.  
  1549.  
  1550.  
  1551.  
  1552. $$ENDIF // end ACTIONMAPPER
  1553. $$ENDIF // end DPLAY
  1554. $$IF(DPLAYVOICE)
  1555. //-----------------------------------------------------------------------------
  1556. // Name: UpdateTalkingVariables()
  1557. // Desc: Update m_bNetworkPlayersTalking and m_bLocalPlayerTalking
  1558. //-----------------------------------------------------------------------------
  1559. VOID CMyD3DApplication::UpdateTalkingVariables()
  1560. {
  1561.     // Enter player critical section before accessing player's state data 
  1562.     // otherwise the DirectPlay network threads may change the data
  1563.     // while this thread is accessing it.
  1564.     PLAYER_LOCK();      
  1565.  
  1566.     APP_PLAYER_INFO* pPlayerInfo = m_PlayInfoList.pNext;
  1567.  
  1568.     m_bNetworkPlayersTalking = FALSE;
  1569.     while( pPlayerInfo != &m_PlayInfoList )
  1570.     {
  1571.         // If any player besides the local player is talking, then set
  1572.         // m_bNetworkPlayersTalking to TRUE
  1573.         if( pPlayerInfo != m_pLocalPlayerInfo && pPlayerInfo->bTalking )
  1574.             m_bNetworkPlayersTalking = TRUE;
  1575.  
  1576.         pPlayerInfo = pPlayerInfo->pNext;
  1577.     }
  1578.  
  1579.     // Update m_bLocalPlayerTalking
  1580.     m_bLocalPlayerTalking = m_pLocalPlayerInfo->bTalking;
  1581.  
  1582.     PLAYER_UNLOCK();                
  1583. }
  1584.  
  1585.  
  1586.  
  1587.  
  1588. $$ENDIF // DPLAYVOICE
  1589. //-----------------------------------------------------------------------------
  1590. // Name: Render()
  1591. // Desc: Called once per frame, the call is the entry point for 3d
  1592. //       rendering. This function sets up render states, clears the
  1593. //       viewport, and renders the scene.
  1594. //-----------------------------------------------------------------------------
  1595. HRESULT CMyD3DApplication::Render()
  1596. {
  1597.     // Clear the viewport
  1598.     m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,
  1599.                          0x000000ff, 1.0f, 0L );
  1600.  
  1601.     // Begin the scene
  1602.     if( SUCCEEDED( m_pd3dDevice->BeginScene() ) )
  1603.     {
  1604.         // TODO: render world
  1605.         
  1606. $$IF(SHOW_TRIANGLE)
  1607.         // Render the vertex buffer contents
  1608.         m_pd3dDevice->SetStreamSource( 0, m_pVB, sizeof(CUSTOMVERTEX) );
  1609.         m_pd3dDevice->SetVertexShader( D3DFVF_CUSTOMVERTEX );
  1610.         m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, 2 );
  1611.  
  1612. $$ENDIF // SHOW_TRIANGLE
  1613. $$IF(SHOW_TEAPOT)
  1614.         // Render the teapot mesh
  1615.         m_pD3DXMesh->DrawSubset(0);
  1616.  
  1617. $$ENDIF // SHOW_TEAPOT
  1618.         // Render stats and help text  
  1619.         RenderText();
  1620.  
  1621.         // End the scene.
  1622.         m_pd3dDevice->EndScene();
  1623.     }
  1624.  
  1625.     return S_OK;
  1626. }
  1627.  
  1628.  
  1629.  
  1630.  
  1631. //-----------------------------------------------------------------------------
  1632. // Name: RenderText()
  1633. // Desc: Renders stats and help text to the scene.
  1634. //-----------------------------------------------------------------------------
  1635. HRESULT CMyD3DApplication::RenderText()
  1636. {
  1637.     D3DCOLOR fontColor        = D3DCOLOR_ARGB(255,255,255,0);
  1638.     D3DCOLOR fontWarningColor = D3DCOLOR_ARGB(255,0,255,255);
  1639.     TCHAR szMsg[MAX_PATH] = TEXT("");
  1640. $$IF(!D3DFONT)
  1641.     RECT rct;
  1642.     ZeroMemory( &rct, sizeof(rct) );       
  1643.  
  1644.     m_pD3DXFont->Begin();
  1645.     rct.left   = 2;
  1646.     rct.right  = m_d3dsdBackBuffer.Width - 20;
  1647. $$ELSE
  1648. $$ENDIF
  1649.  
  1650.     // Output display stats
  1651. $$IF(!D3DFONT)
  1652.     INT nNextLine = 40; 
  1653. $$ELSE
  1654.     FLOAT fNextLine = 40.0f; 
  1655. $$ENDIF
  1656.  
  1657. $$// ******************************************************
  1658.     lstrcpy( szMsg, m_strDeviceStats );
  1659. $$// ------------------------------------------------------
  1660. $$IF(D3DFONT)
  1661.     fNextLine -= 20.0f;
  1662.     m_pFont->DrawText( 2, fNextLine, fontColor, szMsg );
  1663. $$ELSE
  1664.     nNextLine -= 20; rct.top = nNextLine; rct.bottom = rct.top + 20;    
  1665.     m_pD3DXFont->DrawText( szMsg, -1, &rct, 0, fontColor );
  1666. $$ENDIF
  1667. $$// ------------------------------------------------------
  1668.  
  1669. $$// ******************************************************
  1670.     lstrcpy( szMsg, m_strFrameStats );
  1671. $$// ------------------------------------------------------
  1672. $$IF(D3DFONT)
  1673.     fNextLine -= 20.0f;
  1674.     m_pFont->DrawText( 2, fNextLine, fontColor, szMsg );
  1675. $$ELSE
  1676.     nNextLine -= 20; rct.top = nNextLine; rct.bottom = rct.top + 20;    
  1677.     m_pD3DXFont->DrawText( szMsg, -1, &rct, 0, fontColor );
  1678. $$ENDIF
  1679. $$// ------------------------------------------------------
  1680.  
  1681.     // Output statistics & help
  1682. $$IF(!D3DFONT)
  1683.     nNextLine = m_d3dsdBackBuffer.Height; 
  1684. $$ELSE
  1685.     fNextLine = (FLOAT) m_d3dsdBackBuffer.Height; 
  1686. $$ENDIF
  1687.  
  1688. $$IF(DPLAY)
  1689. $$IF(ACTIONMAPPER)
  1690. $$// ******************************************************
  1691.     sprintf( szMsg, TEXT("Network Combined L/R Axis: %0.2f U/D Axis: %0.2f "), 
  1692.               m_CombinedNetworkInput.fAxisRotateLR, m_CombinedNetworkInput.fAxisRotateUD );
  1693. $$// ------------------------------------------------------
  1694. $$IF(D3DFONT)
  1695.     fNextLine -= 20.0f; m_pFont->DrawText( 2, fNextLine, fontColor, szMsg );
  1696. $$ELSE
  1697.     nNextLine -= 20; rct.top = nNextLine; rct.bottom = rct.top + 20;    
  1698.     m_pD3DXFont->DrawText( szMsg, -1, &rct, 0, fontColor );
  1699. $$ENDIF
  1700. $$// ------------------------------------------------------
  1701.  
  1702. $$ELSE // start !ACTIONMAPPER
  1703. $$// ******************************************************
  1704.     wsprintf( szMsg, TEXT("Network Combined Keys: U=%d D=%d L=%d R=%d"), 
  1705.               m_CombinedNetworkInput.bRotateUp, m_CombinedNetworkInput.bRotateDown, m_CombinedNetworkInput.bRotateLeft, m_CombinedNetworkInput.bRotateRight );
  1706. $$// ------------------------------------------------------
  1707. $$IF(D3DFONT)
  1708.     fNextLine -= 20.0f; m_pFont->DrawText( 2, fNextLine, fontColor, szMsg );
  1709. $$ELSE
  1710.     nNextLine -= 20; rct.top = nNextLine; rct.bottom = rct.top + 20;    
  1711.     m_pD3DXFont->DrawText( szMsg, -1, &rct, 0, fontColor );
  1712. $$ENDIF
  1713. $$// ------------------------------------------------------
  1714.  
  1715. $$ENDIF // ACTIONMAPPER
  1716. $$ENDIF // DPLAY
  1717. $$IF(ACTIONMAPPER)
  1718. $$// ******************************************************
  1719. $$IF(DPLAY)
  1720.     sprintf( szMsg, TEXT("Local Left/Right Axis: %0.2f Up/Down Axis: %0.2f "), 
  1721.               m_UserInput.fAxisRotateLR, m_UserInput.fAxisRotateUD );
  1722. $$ELSE
  1723.     sprintf( szMsg, TEXT("Left/Right Axis: %0.2f Up/Down Axis: %0.2f "), 
  1724.               m_UserInput.fAxisRotateLR, m_UserInput.fAxisRotateUD );
  1725. $$ENDIF
  1726. $$// ------------------------------------------------------
  1727. $$IF(D3DFONT)
  1728.     fNextLine -= 20.0f; m_pFont->DrawText( 2, fNextLine, fontColor, szMsg );
  1729. $$ELSE
  1730.     nNextLine -= 20; rct.top = nNextLine; rct.bottom = rct.top + 20;    
  1731.     m_pD3DXFont->DrawText( szMsg, -1, &rct, 0, fontColor );
  1732. $$ENDIF
  1733. $$// ------------------------------------------------------
  1734.  
  1735. $$ELSE // start !ACTIONMAPPER
  1736. $$IF(DPLAY)
  1737. $$// ******************************************************
  1738.     wsprintf( szMsg, TEXT("Local Arrow keys: U=%d D=%d L=%d R=%d"), 
  1739.               m_UserInput.bRotateUp, m_UserInput.bRotateDown, m_UserInput.bRotateLeft, m_UserInput.bRotateRight );
  1740. $$ELSE
  1741.     wsprintf( szMsg, TEXT("Arrow keys: Up=%d Down=%d Left=%d Right=%d"), 
  1742.               m_UserInput.bRotateUp, m_UserInput.bRotateDown, m_UserInput.bRotateLeft, m_UserInput.bRotateRight );
  1743. $$ENDIF
  1744. $$// ------------------------------------------------------
  1745. $$IF(D3DFONT)
  1746.     fNextLine -= 20.0f; m_pFont->DrawText( 2, fNextLine, fontColor, szMsg );
  1747. $$ELSE
  1748.     nNextLine -= 20; rct.top = nNextLine; rct.bottom = rct.top + 20;    
  1749.     m_pD3DXFont->DrawText( szMsg, -1, &rct, 0, fontColor );
  1750. $$ENDIF
  1751. $$// ------------------------------------------------------
  1752.  
  1753. $$ENDIF // ACTIONMAPPER
  1754. $$IF(DPLAY)
  1755. $$// ******************************************************
  1756.     sprintf( szMsg, TEXT("%d player(s) in session %s"), 
  1757.                         m_lNumberOfActivePlayers, 
  1758.                         m_pNetConnectWizard->IsHostPlayer() ? TEXT("(Hosting)") : TEXT("") );
  1759. $$// ------------------------------------------------------
  1760. $$IF(D3DFONT)
  1761.     fNextLine -= 20.0f; m_pFont->DrawText( 2, fNextLine, fontColor, szMsg );
  1762. $$ELSE
  1763.     nNextLine -= 20; rct.top = nNextLine; rct.bottom = rct.top + 20;    
  1764.     m_pD3DXFont->DrawText( szMsg, -1, &rct, 0, fontColor );
  1765. $$ENDIF
  1766. $$// ------------------------------------------------------
  1767.  
  1768. $$ENDIF // DPLAY
  1769. $$IF(DPLAYVOICE)
  1770. $$// ******************************************************
  1771.     sprintf( szMsg, TEXT("Local Player: %s  Network Players: %s"), 
  1772.                         m_bLocalPlayerTalking ? TEXT("Talking") : TEXT("Silent"), 
  1773.                         m_bNetworkPlayersTalking ? TEXT("Talking") : TEXT("Silent") );
  1774. $$// ------------------------------------------------------
  1775. $$IF(D3DFONT)
  1776.     fNextLine -= 20.0f; m_pFont->DrawText( 2, fNextLine, fontColor, szMsg );
  1777. $$ELSE
  1778.     nNextLine -= 20; rct.top = nNextLine; rct.bottom = rct.top + 20;    
  1779.     m_pD3DXFont->DrawText( szMsg, -1, &rct, 0, fontColor );
  1780. $$ENDIF
  1781. $$// ------------------------------------------------------
  1782.  
  1783. $$ENDIF // DPLAYVOICE
  1784. $$IF(!SHOW_TRIANGLE)
  1785. $$IF(!SHOW_TEAPOT)
  1786. $$// ******************************************************
  1787.     sprintf( szMsg, TEXT("World State: %0.3f, %0.3f"), 
  1788.                     m_fWorldRotX, m_fWorldRotY );
  1789. $$// ------------------------------------------------------
  1790. $$IF(D3DFONT)
  1791.     fNextLine -= 20.0f; m_pFont->DrawText( 2, fNextLine, fontColor, szMsg );
  1792. $$ELSE
  1793.     nNextLine -= 20; rct.top = nNextLine; rct.bottom = rct.top + 20;    
  1794.     m_pD3DXFont->DrawText( szMsg, -1, &rct, 0, fontColor );
  1795. $$ENDIF
  1796. $$// ------------------------------------------------------
  1797.  
  1798. $$ENDIF // !SHOW_TEAPOT
  1799. $$ENDIF // !SHOW_TRIANGLE
  1800. $$IF(SHOW_TRIANGLE || SHOW_TEAPOT)
  1801. $$IF(ACTIONMAPPER)
  1802. $$// ******************************************************
  1803.     lstrcpy( szMsg, TEXT("Use arrow keys or joystick to rotate object") );
  1804. $$// ------------------------------------------------------
  1805. $$IF(D3DFONT)
  1806.     fNextLine -= 20.0f; m_pFont->DrawText( 2, fNextLine, fontColor, szMsg );
  1807. $$ELSE
  1808.     nNextLine -= 20; rct.top = nNextLine; rct.bottom = rct.top + 20;    
  1809.     m_pD3DXFont->DrawText( szMsg, -1, &rct, 0, fontColor );
  1810. $$ENDIF
  1811. $$// ------------------------------------------------------
  1812.  
  1813. $$ELSE // start !ACTIONMAPPER
  1814. $$// ******************************************************
  1815.     lstrcpy( szMsg, TEXT("Use arrow keys to rotate object") );
  1816. $$// ------------------------------------------------------
  1817. $$IF(D3DFONT)
  1818.     fNextLine -= 20.0f; m_pFont->DrawText( 2, fNextLine, fontColor, szMsg );
  1819. $$ELSE
  1820.     nNextLine -= 20; rct.top = nNextLine; rct.bottom = rct.top + 20;    
  1821.     m_pD3DXFont->DrawText( szMsg, -1, &rct, 0, fontColor );
  1822. $$ENDIF
  1823. $$// ------------------------------------------------------
  1824.  
  1825. $$ENDIF // ACTIONMAPPER
  1826. $$ELSE // start !(SHOW_TRIANGLE || SHOW_TEAPOT)
  1827. $$IF(ACTIONMAPPER)
  1828. $$// ******************************************************
  1829.     lstrcpy( szMsg, TEXT("Use arrow keys or joystick to update input") );
  1830. $$// ------------------------------------------------------
  1831. $$IF(D3DFONT)
  1832.     fNextLine -= 20.0f; m_pFont->DrawText( 2, fNextLine, fontColor, szMsg );
  1833. $$ELSE
  1834.     nNextLine -= 20; rct.top = nNextLine; rct.bottom = rct.top + 20;    
  1835.     m_pD3DXFont->DrawText( szMsg, -1, &rct, 0, fontColor );
  1836. $$ENDIF
  1837. $$// ------------------------------------------------------
  1838.  
  1839. $$ELSE // start !ACTIONMAPPER
  1840.     lstrcpy( szMsg, TEXT("Use arrow keys to update input") );
  1841. $$// ------------------------------------------------------
  1842. $$IF(D3DFONT)
  1843.     fNextLine -= 20.0f; m_pFont->DrawText( 2, fNextLine, fontColor, szMsg );
  1844. $$ELSE
  1845.     nNextLine -= 20; rct.top = nNextLine; rct.bottom = rct.top + 20;    
  1846.     m_pD3DXFont->DrawText( szMsg, -1, &rct, 0, fontColor );
  1847. $$ENDIF
  1848. $$// ------------------------------------------------------
  1849.  
  1850. $$ENDIF // ACTIONMAPPER
  1851. $$ENDIF // SHOW_TRIANGLE || SHOW_TEAPOT
  1852. $$IF(DMUSIC || DSOUND)
  1853. $$// ******************************************************
  1854.     lstrcpy( szMsg, TEXT("Hold 'F5' down to play and repeat a sound") );
  1855. $$// ------------------------------------------------------
  1856. $$IF(D3DFONT)
  1857.     fNextLine -= 20.0f; m_pFont->DrawText( 2, fNextLine, fontColor, szMsg );
  1858. $$ELSE
  1859.     nNextLine -= 20; rct.top = nNextLine; rct.bottom = rct.top + 20;    
  1860.     m_pD3DXFont->DrawText( szMsg, -1, &rct, 0, fontColor );
  1861. $$ENDIF
  1862. $$// ------------------------------------------------------
  1863.  
  1864. $$ENDIF // DMUSIC || DSOUND
  1865. $$IF(DPLAYVOICE)
  1866. $$// ******************************************************
  1867.     lstrcpy( szMsg, TEXT("Press 'F4' to configure voice") );
  1868. $$// ------------------------------------------------------
  1869. $$IF(D3DFONT)
  1870.     fNextLine -= 20.0f; m_pFont->DrawText( 2, fNextLine, fontColor, szMsg );
  1871. $$ELSE
  1872.     nNextLine -= 20; rct.top = nNextLine; rct.bottom = rct.top + 20;    
  1873.     m_pD3DXFont->DrawText( szMsg, -1, &rct, 0, fontColor );
  1874. $$ENDIF
  1875. $$// ------------------------------------------------------
  1876.  
  1877. $$ENDIF // DPLAYVOICE
  1878. $$IF(ACTIONMAPPER)
  1879. $$// ******************************************************
  1880.     lstrcpy( szMsg, TEXT("Press 'F3' to configure input") );
  1881. $$// ------------------------------------------------------
  1882. $$IF(D3DFONT)
  1883.     fNextLine -= 20.0f; m_pFont->DrawText( 2, fNextLine, fontColor, szMsg );
  1884. $$ELSE
  1885.     nNextLine -= 20; rct.top = nNextLine; rct.bottom = rct.top + 20;    
  1886.     m_pD3DXFont->DrawText( szMsg, -1, &rct, 0, fontColor );
  1887. $$ENDIF
  1888. $$// ------------------------------------------------------
  1889.  
  1890. $$ENDIF // ACTIONMAPPER
  1891. $$// ******************************************************
  1892.     lstrcpy( szMsg, TEXT("Press 'F2' to configure display") );
  1893. $$// ------------------------------------------------------
  1894. $$IF(D3DFONT)
  1895.     fNextLine -= 20.0f; m_pFont->DrawText( 2, fNextLine, fontColor, szMsg );
  1896. $$ELSE
  1897.     nNextLine -= 20; rct.top = nNextLine; rct.bottom = rct.top + 20;    
  1898.     m_pD3DXFont->DrawText( szMsg, -1, &rct, 0, fontColor );
  1899. $$ENDIF
  1900. $$// ------------------------------------------------------
  1901.  
  1902. $$IF(DPLAY)
  1903.     if( m_bHostPausing )
  1904.     {
  1905. $$// ******************************************************
  1906.         lstrcpy( szMsg, TEXT("Paused waiting for host...") );
  1907. $$// ------------------------------------------------------
  1908. $$IF(D3DFONT)
  1909.         fNextLine -= 20.0f; m_pFont->DrawText( 2, fNextLine, fontWarningColor, szMsg );
  1910. $$ELSE
  1911.         nNextLine -= 20; rct.top = nNextLine; rct.bottom = rct.top + 20;    
  1912.         m_pD3DXFont->DrawText( szMsg, -1, &rct, 0, fontWarningColor );
  1913. $$ENDIF
  1914. $$// ------------------------------------------------------   
  1915.     }
  1916.  
  1917. $$ENDIF // DPLAY
  1918. $$IF(!D3DFONT)
  1919.     m_pD3DXFont->End();
  1920.  
  1921. $$ENDIF
  1922.     return S_OK;
  1923. }
  1924.  
  1925.  
  1926.  
  1927.  
  1928. $$IF(DPLAY || ACTIONMAPPER)
  1929. //-----------------------------------------------------------------------------
  1930. // Name: Pause()
  1931. // Desc: Called in to toggle the pause state of the app.
  1932. //-----------------------------------------------------------------------------
  1933. VOID CMyD3DApplication::Pause( BOOL bPause )
  1934. {
  1935. $$IF(DPLAY)
  1936.     // Tell the other apps to pause or unpause if this is the host
  1937.     if( m_pNetConnectWizard && m_pNetConnectWizard->IsHostPlayer() )
  1938.         SendPauseMessageToAll( bPause );
  1939.  
  1940. $$ENDIF
  1941. $$IF(ACTIONMAPPER)
  1942.     // Get access to the list of semantically-mapped input devices
  1943.     // to zero the state of all InputDeviceState structs.  This is needed
  1944.     // because when using DISCL_FOREGROUND, the action mapper will not 
  1945.     // record actions when the focus switches, for example if a dialog appears.
  1946.     // This causes a problem when a button held down when loosing focus, and let
  1947.     // go when the focus is lost.  The app will not record that the button 
  1948.     // has been let go, so the state will be incorrect when focus returns.  
  1949.     // To fix this either use DISCL_BACKGROUND or zero the state when 
  1950.     // loosing focus.
  1951.     CInputDeviceManager::DeviceInfo* pDeviceInfos;
  1952.     DWORD dwNumDevices;
  1953.     m_pInputDeviceManager->GetDevices( &pDeviceInfos, &dwNumDevices );
  1954.  
  1955.     for( DWORD i=0; i<dwNumDevices; i++ )
  1956.     {
  1957.         InputDeviceState* pInputDeviceState = (InputDeviceState*) pDeviceInfos[i].pParam;
  1958.         ZeroMemory( pInputDeviceState, sizeof(InputDeviceState) );
  1959.     }
  1960.  
  1961. $$ENDIF
  1962.     CD3DApplication::Pause( bPause );
  1963. }
  1964.  
  1965.  
  1966.  
  1967.  
  1968. $$ENDIF // DPLAY || ACTIONMAPPER
  1969. //-----------------------------------------------------------------------------
  1970. // Name: MsgProc()
  1971. // Desc: Overrrides the main WndProc, so the sample can do custom message
  1972. //       handling (e.g. processing mouse, keyboard, or menu commands).
  1973. //-----------------------------------------------------------------------------
  1974. LRESULT CMyD3DApplication::MsgProc( HWND hWnd, UINT msg, WPARAM wParam,
  1975.                                     LPARAM lParam )
  1976. {
  1977.     switch( msg )
  1978.     {
  1979.         case WM_PAINT:
  1980.         {
  1981.             if( m_bLoadingApp )
  1982.             {
  1983.                 // Draw on the window tell the user that the app is loading
  1984.                 // TODO: change as needed
  1985.                 HDC hDC = GetDC( hWnd );
  1986.                 TCHAR strMsg[MAX_PATH];
  1987.                 wsprintf( strMsg, TEXT("Loading... Please wait") );
  1988.                 RECT rct;
  1989.                 GetClientRect( hWnd, &rct );
  1990.                 DrawText( hDC, strMsg, -1, &rct, DT_CENTER|DT_VCENTER|DT_SINGLELINE );
  1991.                 ReleaseDC( hWnd, hDC );
  1992.             }
  1993.             break;
  1994.         }
  1995.  
  1996. $$IF(ACTIONMAPPER | DPLAYVOICE)
  1997.         case WM_COMMAND:
  1998.         {
  1999.             switch( LOWORD(wParam) )
  2000.             {
  2001. $$IF(ACTIONMAPPER)
  2002.                 case IDM_CONFIGINPUT:
  2003.                     m_UserInput.bDoConfigureInput = TRUE;
  2004.                     break;
  2005.  
  2006.                 case IDM_CHANGEDEVICE:
  2007.                     m_UserInput.bDoConfigureDisplay = TRUE;
  2008.                     return 0; // Don't hand off to parent
  2009. $$ENDIF 
  2010. $$IF(DPLAYVOICE)
  2011.  
  2012.                 case IDM_CONFIGVOICE:
  2013.                     m_UserInput.bDoConfigureVoice = TRUE;
  2014.                     break;
  2015. $$ENDIF
  2016.             }
  2017.             break;
  2018.         }
  2019.  
  2020. $$ENDIF // end (ACTIONMAPPER | DPLAYVOICE)
  2021.     }
  2022.  
  2023.     return CD3DApplication::MsgProc( hWnd, msg, wParam, lParam );
  2024. }
  2025.  
  2026.  
  2027.  
  2028.  
  2029. $$IF(DPLAYVOICE)
  2030. //-----------------------------------------------------------------------------
  2031. // Name: UserConfigVoice()
  2032. // Desc: Allow user to configure the voice settings
  2033. //-----------------------------------------------------------------------------
  2034. HRESULT CMyD3DApplication::UserConfigVoice()
  2035. {
  2036.     HRESULT hr;
  2037.     BOOL bWasFullscreen = FALSE;
  2038.    
  2039.     // Can't display dialogs in fullscreen mode
  2040.     if( m_bWindowed == FALSE )
  2041.     {
  2042.         bWasFullscreen = TRUE;
  2043.  
  2044.         if( FAILED( ToggleFullscreen() ) )
  2045.         {
  2046.             DisplayErrorMsg( D3DAPPERR_RESIZEFAILED, MSGERR_APPMUSTEXIT );
  2047.             return E_FAIL;
  2048.         }
  2049.     }
  2050.  
  2051.     // Configure the voice settings, store the settings in 
  2052.     // m_guidDVSessionCT & m_dvClientConfig
  2053.     // TODO: replace with a fancier graphics layer like D3D.
  2054.     if( m_pNetVoice )
  2055.     {
  2056.         hr = m_pNetVoice->DoVoiceSetupDialog( g_hInst, m_hWnd, &m_guidDVSessionCT, &m_dvClientConfig );
  2057.  
  2058.         // If the settings dialog was not canceled, then change the settings
  2059.         if( hr != DVERR_USERCANCEL )
  2060.             m_pNetVoice->ChangeVoiceClientSettings( &m_dvClientConfig );
  2061.     }
  2062.  
  2063.     // Return to fullscreen mode after dialogs
  2064.     if( bWasFullscreen )
  2065.     {
  2066.         if( FAILED( ToggleFullscreen() ) )
  2067.         {
  2068.             DisplayErrorMsg( D3DAPPERR_RESIZEFAILED, MSGERR_APPMUSTEXIT );
  2069.             return E_FAIL;
  2070.         }
  2071.     }
  2072.     
  2073.     return S_OK;
  2074. }
  2075.  
  2076.  
  2077.  
  2078.  
  2079. $$ENDIF
  2080. //-----------------------------------------------------------------------------
  2081. // Name: InvalidateDeviceObjects()
  2082. // Desc: Invalidates device objects.  
  2083. //-----------------------------------------------------------------------------
  2084. HRESULT CMyD3DApplication::InvalidateDeviceObjects()
  2085. {
  2086.     // TODO: Cleanup any objects created in RestoreDeviceObjects()
  2087. $$IF(D3DFONT)
  2088.     m_pFont->InvalidateDeviceObjects();
  2089. $$ELSE    
  2090.     SAFE_RELEASE( m_pD3DXFont );
  2091. $$ENDIF
  2092. $$IF(ACTIONMAPPER)
  2093.     SAFE_RELEASE( m_pDIConfigSurface );
  2094. $$ENDIF
  2095.  
  2096.     return S_OK;
  2097. }
  2098.  
  2099.  
  2100.  
  2101.  
  2102. //-----------------------------------------------------------------------------
  2103. // Name: DeleteDeviceObjects()
  2104. // Desc: Called when the app is exiting, or the device is being changed,
  2105. //       this function deletes any device dependent objects.  
  2106. //-----------------------------------------------------------------------------
  2107. HRESULT CMyD3DApplication::DeleteDeviceObjects()
  2108. {
  2109.     // TODO: Cleanup any objects created in InitDeviceObjects()
  2110. $$IF(D3DFONT)
  2111.     m_pFont->DeleteDeviceObjects();
  2112. $$ENDIF
  2113. $$IF(SHOW_TRIANGLE)
  2114.     SAFE_RELEASE( m_pVB );
  2115. $$ENDIF
  2116. $$IF(SHOW_TEAPOT)
  2117.     SAFE_RELEASE( m_pD3DXMesh );
  2118. $$ENDIF
  2119.  
  2120.     return S_OK;
  2121. }
  2122.  
  2123.  
  2124.  
  2125.  
  2126. //-----------------------------------------------------------------------------
  2127. // Name: FinalCleanup()
  2128. // Desc: Called before the app exits, this function gives the app the chance
  2129. //       to cleanup after itself.
  2130. //-----------------------------------------------------------------------------
  2131. HRESULT CMyD3DApplication::FinalCleanup()
  2132. {
  2133.     // TODO: Perform any final cleanup needed
  2134. $$IF(D3DFONT)
  2135.     // Cleanup D3D font
  2136.     SAFE_DELETE( m_pFont );
  2137.  
  2138. $$ENDIF
  2139. $$IF(DINPUT)
  2140.     // Cleanup DirectInput
  2141.     CleanupDirectInput();
  2142.  
  2143. $$ENDIF
  2144. $$IF(DMUSIC || DSOUND)
  2145.     // Cleanup DirectX audio objects
  2146.     SAFE_DELETE( m_pBounceSound );
  2147. $$IF(DMUSIC)
  2148.     SAFE_DELETE( m_pMusicManager );
  2149. $$ELSE // start !DMUSIC
  2150.     SAFE_DELETE( m_pSoundManager );
  2151. $$ENDIF // end DMUSIC
  2152.  
  2153. $$ENDIF // end (DMUSIC || DSOUND)
  2154. $$IF(DPLAY)
  2155.     // Cleanup DirectPlay
  2156.     CleanupDirectPlay();
  2157.  
  2158.     // Cleanup COM
  2159.     CoUninitialize();
  2160.  
  2161. $$ENDIF
  2162.     // Write the settings to the registry
  2163.     WriteSettings();
  2164.  
  2165.     return S_OK;
  2166. }
  2167.  
  2168.  
  2169.  
  2170.  
  2171. $$IF(DPLAY)
  2172. //-----------------------------------------------------------------------------
  2173. // Name: StaticDirectPlayMessageHandler
  2174. // Desc: Static callback helper to call into CMyD3DApplication class
  2175. //-----------------------------------------------------------------------------
  2176. HRESULT WINAPI CMyD3DApplication::StaticDirectPlayMessageHandler( PVOID pvUserContext, 
  2177.                                                                   DWORD dwMessageId, 
  2178.                                                                   PVOID pMsgBuffer )
  2179. {
  2180.     if( g_pApp )
  2181.         return g_pApp->DirectPlayMessageHandler( pvUserContext, dwMessageId, pMsgBuffer );
  2182.     return S_OK;
  2183. }
  2184.  
  2185.  
  2186.  
  2187.  
  2188. //-----------------------------------------------------------------------------
  2189. // Name: DirectPlayMessageHandler
  2190. // Desc: Handler for DirectPlay messages.  This function is called by
  2191. //       the DirectPlay message handler pool of threads, so be careful of thread
  2192. //       synchronization problems with shared memory
  2193. //-----------------------------------------------------------------------------
  2194. HRESULT CMyD3DApplication::DirectPlayMessageHandler( PVOID pvUserContext, 
  2195.                                                      DWORD dwMessageId, 
  2196.                                                      PVOID pMsgBuffer )
  2197. {
  2198.     // Try not to stay in this message handler for too long, otherwise
  2199.     // there will be a backlog of data.  The best solution is to 
  2200.     // queue data as it comes in, and then handle it on other threads.
  2201.     
  2202.     // This function is called by the DirectPlay message handler pool of 
  2203.     // threads, so be careful of thread synchronization problems with shared memory
  2204.  
  2205.     switch( dwMessageId )
  2206.     {
  2207.         case DPN_MSGID_CREATE_PLAYER:
  2208.         {
  2209.             HRESULT hr;
  2210.             PDPNMSG_CREATE_PLAYER pCreatePlayerMsg;
  2211.             pCreatePlayerMsg = (PDPNMSG_CREATE_PLAYER)pMsgBuffer;
  2212.  
  2213.             // Get the peer info and extract its name
  2214.             DWORD dwSize = 0;
  2215.             DPN_PLAYER_INFO* pdpPlayerInfo = NULL;
  2216.             hr = m_pDP->GetPeerInfo( pCreatePlayerMsg->dpnidPlayer, 
  2217.                                      pdpPlayerInfo, &dwSize, 0 );
  2218.             if( FAILED(hr) && hr != DPNERR_BUFFERTOOSMALL )
  2219.                 return DXTRACE_ERR( TEXT("GetPeerInfo"), hr );
  2220.             pdpPlayerInfo = (DPN_PLAYER_INFO*) new BYTE[ dwSize ];
  2221.             ZeroMemory( pdpPlayerInfo, dwSize );
  2222.             pdpPlayerInfo->dwSize = sizeof(DPN_PLAYER_INFO);
  2223.             hr = m_pDP->GetPeerInfo( pCreatePlayerMsg->dpnidPlayer, 
  2224.                                      pdpPlayerInfo, &dwSize, 0 );
  2225.             if( FAILED(hr) )
  2226.                 return DXTRACE_ERR( TEXT("GetPeerInfo"), hr );
  2227.  
  2228.             // Create a new and fill in a APP_PLAYER_INFO
  2229.             APP_PLAYER_INFO* pPlayerInfo = new APP_PLAYER_INFO;
  2230.             ZeroMemory( pPlayerInfo, sizeof(APP_PLAYER_INFO) );
  2231.             pPlayerInfo->lRefCount   = 1;
  2232.             pPlayerInfo->dpnidPlayer = pCreatePlayerMsg->dpnidPlayer;
  2233.  
  2234.             // This stores a extra TCHAR copy of the player name for 
  2235.             // easier access.  This will be redundant copy since DPlay 
  2236.             // also keeps a copy of the player name in GetPeerInfo()
  2237.             DXUtil_ConvertWideStringToGeneric( pPlayerInfo->strPlayerName, 
  2238.                                                pdpPlayerInfo->pwszName, MAX_PATH );
  2239.  
  2240.             if( pdpPlayerInfo->dwPlayerFlags & DPNPLAYER_LOCAL )
  2241.             {
  2242.                 m_dpnidLocalPlayer = pCreatePlayerMsg->dpnidPlayer;
  2243.                 m_pLocalPlayerInfo = pPlayerInfo;
  2244.  
  2245.                 // Increase the ref if this is the local player, so the struct 
  2246.                 // won't be deleted when DirectPlay shuts down.  The
  2247.                 // main window thread will release the struct when it is done
  2248.                 pPlayerInfo->lRefCount++;
  2249.             }
  2250.             else
  2251.             {
  2252.                 if( m_pNetConnectWizard->IsHostPlayer() )
  2253.                 {
  2254.                     // If the local player is the host and 
  2255.                     // this DPN_MSGID_CREATE_PLAYER is not for the local player
  2256.                     // then set the m_fWorldSyncTimer to fire immediately so
  2257.                     // the new player will get the state of the world
  2258.                     m_fWorldSyncTimer = 0.0f;
  2259.                 }
  2260.             }
  2261.  
  2262.             // Add the APP_PLAYER_INFO to the circular linked list, m_PlayInfoList
  2263.             pPlayerInfo->pNext = m_PlayInfoList.pNext;
  2264.             pPlayerInfo->pPrev = &m_PlayInfoList;
  2265.             m_PlayInfoList.pNext->pPrev = pPlayerInfo;    
  2266.             m_PlayInfoList.pNext = pPlayerInfo;    
  2267.  
  2268.             SAFE_DELETE_ARRAY( pdpPlayerInfo );
  2269.  
  2270.             // Tell DirectPlay to store this pPlayerInfo 
  2271.             // pointer in the pvPlayerContext.
  2272.             pCreatePlayerMsg->pvPlayerContext = pPlayerInfo;
  2273.  
  2274.             // Update the number of active players, and if the app needs to 
  2275.             // tell the UI immediately about this, then post a message to 
  2276.             // the window thread.  This keeps the DirectPlay message handler 
  2277.             // from blocking
  2278.             InterlockedIncrement( &m_lNumberOfActivePlayers );
  2279.             break;
  2280.         }
  2281.  
  2282.         case DPN_MSGID_RECEIVE:
  2283.         {
  2284.             PDPNMSG_RECEIVE pReceiveMsg;
  2285.             pReceiveMsg = (PDPNMSG_RECEIVE)pMsgBuffer;
  2286.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pReceiveMsg->pvPlayerContext;
  2287.  
  2288.             GAMEMSG_GENERIC* pMsg = (GAMEMSG_GENERIC*) pReceiveMsg->pReceiveData;
  2289.             switch( pMsg->nType )
  2290.             {
  2291.                 case GAME_MSGID_INPUTSTATE:
  2292.                 {
  2293.                     // Update the APP_PLAYER_INFO struct associated with this
  2294.                     // network player with the data send in the GAMEMSG_INPUTSTATE.
  2295.                     GAMEMSG_INPUTSTATE* pInputStateMsg = (GAMEMSG_INPUTSTATE*) pMsg;
  2296.  
  2297.                     // Enter player critical section before accessing player's state data 
  2298.                     // otherwise the main thread or other DirectPlay threads may access the data
  2299.                     // while this thread is changing it.
  2300.                     PLAYER_LOCK();                  
  2301.  
  2302. $$IF(ACTIONMAPPER)
  2303.                     pPlayerInfo->fAxisRotateLR = pInputStateMsg->fAxisRotateLR;
  2304.                     pPlayerInfo->fAxisRotateUD = pInputStateMsg->fAxisRotateUD;
  2305. $$ELSE
  2306.                     pPlayerInfo->bRotateUp    = pInputStateMsg->bRotateUp;
  2307.                     pPlayerInfo->bRotateDown  = pInputStateMsg->bRotateDown;
  2308.                     pPlayerInfo->bRotateLeft  = pInputStateMsg->bRotateLeft;
  2309.                     pPlayerInfo->bRotateRight = pInputStateMsg->bRotateRight;
  2310. $$ENDIF
  2311.  
  2312.                     PLAYER_UNLOCK();                // leave player context CS
  2313.                     break;
  2314.                 }
  2315.  
  2316.                 case GAME_MSGID_WORLDSTATE:
  2317.                 {
  2318.                     // Enter world state critical section before accessing world state data 
  2319.                     // otherwise the main thread or other DirectPlay threads may access the data
  2320.                     // while this thread is changing it.
  2321.                     WORLD_LOCK();
  2322.  
  2323.                     // Update the world state with the data from GAMEMSG_WORLDSTATE
  2324.                     GAMEMSG_WORLDSTATE* pMsgWorldState = (GAMEMSG_WORLDSTATE*) pMsg;
  2325.                     m_fWorldRotX = pMsgWorldState->fWorldRotX;
  2326.                     m_fWorldRotY = pMsgWorldState->fWorldRotY;
  2327.  
  2328.                     // Leave the critical section
  2329.                     WORLD_UNLOCK();
  2330.                     break;
  2331.                 }
  2332.  
  2333.                 case GAME_MSGID_HOSTPAUSE:
  2334.                 {
  2335.                     GAMEMSG_HOSTPAUSE* pMsgPause = (GAMEMSG_HOSTPAUSE*) pMsg;
  2336.  
  2337.                     // Update the pause state with the data from GAMEMSG_HOSTPAUSE
  2338.                     m_bHostPausing = pMsgPause->bHostPause;
  2339.                     break;
  2340.                 }
  2341.             }
  2342.             break;
  2343.         }
  2344.  
  2345.         case DPN_MSGID_DESTROY_PLAYER:
  2346.         {
  2347.             PDPNMSG_DESTROY_PLAYER pDestroyPlayerMsg;
  2348.             pDestroyPlayerMsg = (PDPNMSG_DESTROY_PLAYER)pMsgBuffer;
  2349.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pDestroyPlayerMsg->pvPlayerContext;
  2350.  
  2351.             PLAYER_LOCK();                  // enter player context CS
  2352.  
  2353.             // Remove pPlayerInfo from the circular linked list
  2354.             pPlayerInfo->pNext->pPrev = pPlayerInfo->pPrev;
  2355.             pPlayerInfo->pPrev->pNext = pPlayerInfo->pNext;
  2356.  
  2357.             PLAYER_RELEASE( pPlayerInfo );  // Release player and cleanup if needed
  2358.             PLAYER_UNLOCK();                // leave player context CS
  2359.  
  2360.             // Update the number of active players, and if the app needs to 
  2361.             // tell the UI immediately about this, then post a message to 
  2362.             // the window thread.  This keeps the DirectPlay message handler 
  2363.             // from blocking
  2364.             InterlockedDecrement( &m_lNumberOfActivePlayers );
  2365.             break;
  2366.         }
  2367.  
  2368.         case DPN_MSGID_TERMINATE_SESSION:
  2369.         {
  2370.             PDPNMSG_TERMINATE_SESSION pTerminateSessionMsg;
  2371.             pTerminateSessionMsg = (PDPNMSG_TERMINATE_SESSION)pMsgBuffer;
  2372.  
  2373.             m_hrNet = DPNERR_CONNECTIONLOST;
  2374.  
  2375.             // Close the window, which shuts down the app
  2376.             if( m_hWnd )
  2377.                 PostMessage( m_hWnd, WM_CLOSE, 0, 0 );
  2378.             break;
  2379.         }
  2380.     }
  2381.  
  2382.     // Make sure the DirectPlay MessageHandler calls the CNetConnectWizard handler, 
  2383.     // so it can be informed of messages such as DPN_MSGID_ENUM_HOSTS_RESPONSE.
  2384.     if( m_pNetConnectWizard )
  2385.         return m_pNetConnectWizard->MessageHandler( pvUserContext, dwMessageId, 
  2386.                                                     pMsgBuffer );
  2387.     
  2388.     return S_OK;
  2389. }
  2390.  
  2391.  
  2392.  
  2393.  
  2394. //-----------------------------------------------------------------------------
  2395. // Name: StaticDirectPlayLobbyMessageHandler
  2396. // Desc: Static callback helper to call into CMyD3DApplication class
  2397. //-----------------------------------------------------------------------------
  2398. HRESULT WINAPI CMyD3DApplication::StaticDirectPlayLobbyMessageHandler( PVOID pvUserContext, 
  2399.                                                                   DWORD dwMessageId, 
  2400.                                                                   PVOID pMsgBuffer )
  2401. {
  2402.     if( g_pApp )
  2403.         return g_pApp->DirectPlayLobbyMessageHandler( pvUserContext, dwMessageId, pMsgBuffer );
  2404.     return S_OK;
  2405. }
  2406.  
  2407.  
  2408.  
  2409.  
  2410. //-----------------------------------------------------------------------------
  2411. // Name: DirectPlayLobbyMessageHandler
  2412. // Desc: Handler for DirectPlay lobby messages.  This function is called by
  2413. //       the DirectPlay lobby message handler pool of threads, so be careful of 
  2414. //       thread synchronization problems with shared memory
  2415. //-----------------------------------------------------------------------------
  2416. HRESULT CMyD3DApplication::DirectPlayLobbyMessageHandler( PVOID pvUserContext, 
  2417.                                                           DWORD dwMessageId, 
  2418.                                                           PVOID pMsgBuffer )
  2419. {
  2420.     switch( dwMessageId )
  2421.     {
  2422.         case DPL_MSGID_CONNECT:
  2423.         {
  2424.             PDPL_MESSAGE_CONNECT pConnectMsg;
  2425.             pConnectMsg = (PDPL_MESSAGE_CONNECT)pMsgBuffer;
  2426.  
  2427.             // The CNetConnectWizard will handle this message for us,
  2428.             // so there is nothing we need to do here for this simple
  2429.             // sample.
  2430.             break;
  2431.         }
  2432.  
  2433.         case DPL_MSGID_DISCONNECT:
  2434.         {
  2435.             PDPL_MESSAGE_DISCONNECT pDisconnectMsg;
  2436.             pDisconnectMsg = (PDPL_MESSAGE_DISCONNECT)pMsgBuffer;
  2437.  
  2438.             // We should free any data associated with the lobby 
  2439.             // client here, but there is none.
  2440.             break;
  2441.         }
  2442.  
  2443.         case DPL_MSGID_RECEIVE:
  2444.         {
  2445.             PDPL_MESSAGE_RECEIVE pReceiveMsg;
  2446.             pReceiveMsg = (PDPL_MESSAGE_RECEIVE)pMsgBuffer;
  2447.  
  2448.             // The lobby client sent us data.  This sample doesn't
  2449.             // expected data from the client, but it is useful 
  2450.             // for more complex apps.
  2451.             break;
  2452.         }
  2453.  
  2454.         case DPL_MSGID_CONNECTION_SETTINGS:
  2455.         {
  2456.             PDPL_MESSAGE_CONNECTION_SETTINGS pConnectionStatusMsg;
  2457.             pConnectionStatusMsg = (PDPL_MESSAGE_CONNECTION_SETTINGS)pMsgBuffer;
  2458.  
  2459.             // The lobby client has changed the connection settings.  
  2460.             // This simple sample doesn't handle this, but more complex apps may
  2461.             // want to.
  2462.             break;
  2463.         }
  2464.     }
  2465.  
  2466.     // Make sure the DirectPlay MessageHandler calls the CNetConnectWizard handler, 
  2467.     // so the wizard can be informed of lobby messages such as DPL_MSGID_CONNECT
  2468.     if( m_pNetConnectWizard )
  2469.         return m_pNetConnectWizard->LobbyMessageHandler( pvUserContext, dwMessageId, 
  2470.                                                          pMsgBuffer );
  2471.     
  2472.     return S_OK;
  2473. }
  2474.  
  2475.  
  2476.  
  2477.  
  2478. $$ENDIF
  2479. $$IF(DPLAYVOICE)
  2480. //-----------------------------------------------------------------------------
  2481. // Name: StaticDirectPlayVoiceServerMessageHandler
  2482. // Desc: Static callback helper to call into CMyD3DApplication class
  2483. //-----------------------------------------------------------------------------
  2484. HRESULT WINAPI CMyD3DApplication::StaticDirectPlayVoiceServerMessageHandler( PVOID pvUserContext, 
  2485.                                                                   DWORD dwMessageId, 
  2486.                                                                   PVOID pMsgBuffer )
  2487. {
  2488.     if( g_pApp )
  2489.         return g_pApp->DirectPlayVoiceServerMessageHandler( pvUserContext, dwMessageId, pMsgBuffer );
  2490.     return S_OK;
  2491. }
  2492.  
  2493.  
  2494.  
  2495.  
  2496. //-----------------------------------------------------------------------------
  2497. // Name: DirectPlayVoiceServerMessageHandler()
  2498. // Desc: The callback for DirectPlayVoice server messages.  
  2499. //-----------------------------------------------------------------------------
  2500. HRESULT CMyD3DApplication::DirectPlayVoiceServerMessageHandler( LPVOID lpvUserContext, DWORD dwMessageType,
  2501.                                                                 LPVOID lpMessage )
  2502. {
  2503.     // This simple sample doesn't respond to any server messages
  2504.     return S_OK;
  2505. }
  2506.  
  2507.  
  2508.  
  2509.  
  2510. //-----------------------------------------------------------------------------
  2511. // Name: StaticDirectPlayVoiceClientMessageHandler
  2512. // Desc: Static callback helper to call into CMyD3DApplication class
  2513. //-----------------------------------------------------------------------------
  2514. HRESULT WINAPI CMyD3DApplication::StaticDirectPlayVoiceClientMessageHandler( PVOID pvUserContext, 
  2515.                                                                   DWORD dwMessageId, 
  2516.                                                                   PVOID pMsgBuffer )
  2517. {
  2518.     if( g_pApp )
  2519.         return g_pApp->DirectPlayVoiceClientMessageHandler( pvUserContext, dwMessageId, pMsgBuffer );
  2520.     return S_OK;
  2521. }
  2522.  
  2523.  
  2524.  
  2525.  
  2526. //-----------------------------------------------------------------------------
  2527. // Name: DirectPlayVoiceClientMessageHandler()
  2528. // Desc: The callback for DirectPlayVoice client messages.  
  2529. //       This handles client messages and updates the UI the whenever a client 
  2530. //       starts or stops talking.  
  2531. //-----------------------------------------------------------------------------
  2532. HRESULT CMyD3DApplication::DirectPlayVoiceClientMessageHandler( LPVOID lpvUserContext, DWORD dwMessageType,
  2533.                                                                 LPVOID lpMessage )
  2534. {
  2535.     // Try not to stay in this message handler for too long, otherwise
  2536.     // there will be a backlog of data.  The best solution is to 
  2537.     // queue data as it comes in, and then handle it on other threads.
  2538.     
  2539.     // This function is called by the DirectPlay message handler pool of 
  2540.     // threads, so be care of thread synchronization problems with shared memory
  2541.  
  2542.     HRESULT hr;
  2543.     HWND hDlg = (HWND) lpvUserContext;
  2544.  
  2545.     switch( dwMessageType )
  2546.     {
  2547.         case DVMSGID_CREATEVOICEPLAYER:
  2548.         {
  2549.             DVMSG_CREATEVOICEPLAYER* pCreateVoicePlayerMsg = (DVMSG_CREATEVOICEPLAYER*) lpMessage;
  2550.             APP_PLAYER_INFO* pPlayerInfo = NULL;
  2551.  
  2552.             // Enter player critical section before accessing player's state data 
  2553.             // otherwise the main thread or other DirectPlay threads may access the data
  2554.             // while this thread is changing it.
  2555.             PLAYER_LOCK(); 
  2556.  
  2557.             // Get the player context associated with this DPNID
  2558.             hr = m_pDP->GetPlayerContext( pCreateVoicePlayerMsg->dvidPlayer, 
  2559.                                           (LPVOID* const) &pPlayerInfo, 0);
  2560.  
  2561.             if( FAILED(hr) || pPlayerInfo == NULL )
  2562.             {
  2563.                 // The player who sent this may have gone away before this 
  2564.                 // message was handled, so just ignore it
  2565.                 PLAYER_UNLOCK();
  2566.                 break;
  2567.             }
  2568.  
  2569.             // Addref player struct, so it can used freely by the voice layer
  2570.             PLAYER_ADDREF( pPlayerInfo ); 
  2571.  
  2572.             pPlayerInfo->bHalfDuplex = ((pCreateVoicePlayerMsg->dwFlags & DVPLAYERCAPS_HALFDUPLEX) != 0);
  2573.  
  2574.             PLAYER_UNLOCK(); // leave player context CS
  2575.  
  2576.             // Set voice context value
  2577.             pCreateVoicePlayerMsg->pvPlayerContext = pPlayerInfo;
  2578.  
  2579.             // We're leaving the extra reference, so the voice layer will 
  2580.             // own that reference
  2581.             break;
  2582.         }
  2583.  
  2584.         case DVMSGID_DELETEVOICEPLAYER:
  2585.         {
  2586.             DVMSG_DELETEVOICEPLAYER* pMsg = (DVMSG_DELETEVOICEPLAYER*) lpMessage;
  2587.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pMsg->pvPlayerContext;
  2588.  
  2589.             // Release our extra reference on the player info that we have for the voice
  2590.             // context value.  
  2591.             PLAYER_LOCK();
  2592.             PLAYER_RELEASE( pPlayerInfo );  
  2593.             PLAYER_UNLOCK();
  2594.             break;
  2595.         }            
  2596.  
  2597.         case DVMSGID_RECORDSTART:             
  2598.         { 
  2599.             DVMSG_RECORDSTART* pMsg = (DVMSG_RECORDSTART*) lpMessage;
  2600.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pMsg->pvLocalPlayerContext;
  2601.  
  2602.             PLAYER_LOCK();
  2603.             if( pPlayerInfo )
  2604.                 pPlayerInfo->bTalking = TRUE;   
  2605.             PLAYER_UNLOCK();
  2606.             break;
  2607.         }
  2608.  
  2609.         case DVMSGID_RECORDSTOP:             
  2610.         {
  2611.             DVMSG_RECORDSTOP* pMsg = (DVMSG_RECORDSTOP*) lpMessage;
  2612.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pMsg->pvLocalPlayerContext;
  2613.  
  2614.             PLAYER_LOCK();
  2615.             if( pPlayerInfo )
  2616.                 pPlayerInfo->bTalking = FALSE;  
  2617.             PLAYER_UNLOCK();
  2618.             break;
  2619.         }
  2620.  
  2621.         case DVMSGID_PLAYERVOICESTART:
  2622.         {
  2623.             DVMSG_PLAYERVOICESTART* pMsg = (DVMSG_PLAYERVOICESTART*) lpMessage;
  2624.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pMsg->pvPlayerContext;
  2625.  
  2626.             PLAYER_LOCK();
  2627.             if( pPlayerInfo )
  2628.                 pPlayerInfo->bTalking = TRUE;   
  2629.             PLAYER_UNLOCK();
  2630.             break;
  2631.         }
  2632.  
  2633.         case DVMSGID_PLAYERVOICESTOP:
  2634.         {
  2635.             DVMSG_PLAYERVOICESTOP* pMsg = (DVMSG_PLAYERVOICESTOP*) lpMessage;
  2636.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pMsg->pvPlayerContext;
  2637.  
  2638.             PLAYER_LOCK();
  2639.             if( pPlayerInfo )
  2640.                 pPlayerInfo->bTalking = FALSE;  
  2641.             PLAYER_UNLOCK();
  2642.             break;
  2643.         }
  2644.     }
  2645.  
  2646.     return S_OK;
  2647. }
  2648.  
  2649.  
  2650.  
  2651.  
  2652. $$ENDIF
  2653. $$IF(DPLAY)
  2654. //-----------------------------------------------------------------------------
  2655. // Name: CleanupDirectPlay()
  2656. // Desc: Cleanup DirectPlay 
  2657. //-----------------------------------------------------------------------------
  2658. VOID CMyD3DApplication::CleanupDirectPlay()
  2659. {
  2660. $$IF(DPLAYVOICE)
  2661.     // Disconnect from the DirectPlayVoice session, 
  2662.     // and destroy it if we are the host player.
  2663.     SAFE_DELETE( m_pNetVoice ); 
  2664.  
  2665. $$ENDIF
  2666.     // Cleanup DirectPlay and helper classes
  2667.     if( m_pNetConnectWizard )
  2668.         m_pNetConnectWizard->Shutdown();
  2669.  
  2670.     if( m_pDP )
  2671.     {
  2672.         m_pDP->Close(0);
  2673.         SAFE_RELEASE( m_pDP );
  2674.     }
  2675.  
  2676.     if( m_pLobbiedApp )
  2677.     {
  2678.         m_pLobbiedApp->Close( 0 );
  2679.         SAFE_RELEASE( m_pLobbiedApp );
  2680.     }    
  2681.  
  2682.     PLAYER_LOCK();                  // enter player context CS
  2683.     PLAYER_RELEASE( m_pLocalPlayerInfo ); // Release player and cleanup if needed
  2684.     PLAYER_UNLOCK();                // leave player context CS
  2685.  
  2686.     // Don't delete the wizard until we know that 
  2687.     // DirectPlay is out of its message handlers.
  2688.     // This will be true after Close() has been called. 
  2689.     SAFE_DELETE( m_pNetConnectWizard );
  2690.     DeleteCriticalSection( &g_csPlayerContext );
  2691.     DeleteCriticalSection( &g_csWorldStateContext );
  2692.  
  2693.     if( m_hrNet == DPNERR_CONNECTIONLOST )
  2694.     {
  2695.         MessageBox( m_hWnd, TEXT("The DirectPlay session was lost. ")
  2696.                     TEXT("The sample will now quit."),
  2697.                     TEXT("DirectPlay Sample"), MB_OK | MB_ICONERROR );
  2698.     }
  2699. }
  2700.  
  2701.  
  2702.  
  2703. $$ENDIF
  2704. $$IF(DINPUT)
  2705. //-----------------------------------------------------------------------------
  2706. // Name: CleanupDirectInput()
  2707. // Desc: Cleanup DirectInput 
  2708. //-----------------------------------------------------------------------------
  2709. VOID CMyD3DApplication::CleanupDirectInput()
  2710. {
  2711. $$IF(KEYBOARD)
  2712.     // Cleanup DirectX input objects
  2713.     SAFE_RELEASE( m_pKeyboard );
  2714.     SAFE_RELEASE( m_pDI );
  2715.  
  2716. $$ENDIF
  2717. $$IF(ACTIONMAPPER)
  2718.     if( NULL == m_pInputDeviceManager )
  2719.         return;
  2720.  
  2721.     // Get access to the list of semantically-mapped input devices
  2722.     // to delete all InputDeviceState structs
  2723.     CInputDeviceManager::DeviceInfo* pDeviceInfos;
  2724.     DWORD dwNumDevices;
  2725.     m_pInputDeviceManager->GetDevices( &pDeviceInfos, &dwNumDevices );
  2726.  
  2727.     for( DWORD i=0; i<dwNumDevices; i++ )
  2728.     {
  2729.         InputDeviceState* pInputDeviceState = (InputDeviceState*) pDeviceInfos[i].pParam;
  2730.         SAFE_DELETE( pInputDeviceState );
  2731.         pDeviceInfos[i].pParam = NULL;
  2732.     }
  2733.  
  2734.     // Cleanup DirectX input objects
  2735.     SAFE_DELETE( m_pInputDeviceManager );
  2736.  
  2737. $$ENDIF
  2738. }
  2739.  
  2740.  
  2741.  
  2742.  
  2743. $$ENDIF
  2744.